source: java/FramclipsePlugin/src/main/java/com/framsticks/framclipse/editors/codeCompletion/FramscriptCompletionProcessor.java @ 193

Last change on this file since 193 was 193, checked in by Maciej Komosinski, 10 years ago

Set svn:eol-style native for all textual files

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/plain
File size: 11.6 KB
Line 
1package com.framsticks.framclipse.editors.codeCompletion;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.List;
6import java.util.Set;
7
8import org.eclipse.jface.text.IDocument;
9import org.eclipse.jface.text.ITextViewer;
10import org.eclipse.jface.text.TextPresentation;
11import org.eclipse.jface.text.contentassist.ContextInformation;
12import org.eclipse.jface.text.contentassist.ICompletionProposal;
13import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
14import org.eclipse.jface.text.contentassist.IContextInformation;
15import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
16import org.eclipse.jface.text.contentassist.IContextInformationValidator;
17import org.eclipse.ui.IEditorInput;
18import org.eclipse.ui.IFileEditorMapping;
19import org.eclipse.ui.IPathEditorInput;
20import org.jdom.Attribute;
21import org.jdom.Document;
22import org.jdom.Element;
23import org.jdom.xpath.XPath;
24
25import com.framsticks.framclipse.Framclipse;
26import com.framsticks.framclipse.editors.EditorType;
27import com.framsticks.framclipse.editors.FramclipseEditor;
28import com.framsticks.framclipse.internal.parser.ASTFObject;
29import com.framsticks.framclipse.internal.parser.ASTGlobalInclude;
30import com.framsticks.framclipse.internal.parser.ASTProperty;
31import com.framsticks.framclipse.internal.parser.FramclipseParser;
32import com.framsticks.framclipse.internal.parser.Node;
33import com.framsticks.framclipse.syntaxColoring.FramscriptCodeScanner;
34
35
36/**
37 * Framscript completion processor.
38 */
39public class FramscriptCompletionProcessor implements IContentAssistProcessor {
40
41        private final Set<String> contexts;
42
43        protected final FramclipseEditor editor;
44
45        protected final EditorType editorType;
46
47        protected FramclipseParser parser;
48
49        public FramscriptCompletionProcessor(Set<String> contexts,
50                        FramclipseEditor editor, EditorType editorType) {
51                super();
52                this.contexts = contexts;
53                this.editor = editor;
54                this.editorType = editorType;
55        }
56
57        protected IContextInformationValidator validator = new Validator();
58
59        /*
60         * (non-Javadoc) Method declared on IContentAssistProcessor
61         */
62        @SuppressWarnings("unchecked")
63        public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer,
64                        int documentOffset) {
65
66                // get text before cursor
67                IDocument document = viewer.getDocument();
68                String elementPart = SyntaxUtils.getElementBefore(document,
69                                documentOffset);
70
71                // check if there is a dot before this text -> then fetch parent
72                int offset = documentOffset - elementPart.length() - 1;
73
74                String parent = null;
75                List<String> elementsBefore = SyntaxUtils.getElementsBefore(document,
76                                offset);
77                try {
78                        parent = SyntaxUtils.getLastElementType(elementsBefore);
79                } catch (Exception e1) {
80                        e1.printStackTrace();
81                }
82
83                // now if we have parent, ask XPath
84                List<OrderableCompletionProposal> proposals = new ArrayList<OrderableCompletionProposal>();
85                if (EditorType.EXPDEF.equals(editorType) && "ExpParams".equals(parent)) {
86                        addExpParamsProposals(viewer.getDocument(), documentOffset,
87                                        elementPart, proposals);
88                } else {
89                        String query = SyntaxUtils.ROOT + "/*";
90                        if ((parent != null) && (parent.length() > 0)) {
91                                query += "[@" + SyntaxUtils.NAME_ATTRIBUTE + "='" + parent
92                                                + "']/" + SyntaxUtils.ELEMENT_ELEMENT;
93                        }
94                        Document syntax = Framclipse.getDefault().getFramscriptSyntax();
95                        try {
96                                XPath xpath = XPath.newInstance(query);
97                                List<Element> list = xpath.selectNodes(syntax);
98                                for (Element element : list) {
99                                        Attribute context = element
100                                                        .getAttribute(SyntaxUtils.CONTEXT_ATTRIBUTE);
101                                        if ((context == null)
102                                                        || contexts.contains(context.getValue())) {
103                                                addCompletion(element, documentOffset, elementPart,
104                                                                proposals);
105                                        }
106                                }
107                        } catch (Exception e) {
108                                e.printStackTrace();
109                        }
110                }
111                if (parent == null || parent.length() == 0)
112                        addKeywordProposals(documentOffset, elementPart, proposals);
113
114                Collections.sort(proposals);
115
116                ICompletionProposal[] result = new ICompletionProposal[proposals.size()];
117                result = proposals.toArray(result);
118                return result;
119        }
120
121        void addExpParamsProposals(IDocument document, int documentOffset,
122                        String elementPart, List<OrderableCompletionProposal> proposals) {
123                Node model = editor.getFileModel();
124                if (model == null)
125                        return;
126                processExpParamNode(model, documentOffset, elementPart, proposals);
127        }
128
129        static void processExpParamNode(Node model, int documentOffset,
130                        String elementPart, List<OrderableCompletionProposal> proposals) {
131                {
132                        final int modelNumChild = model.jjtGetNumChildren();
133                        for (int i = 0; i < modelNumChild; ++i) {
134                                final Node child = model.jjtGetChild(i);
135                                if (child instanceof ASTFObject) {
136                                        final ASTFObject fo = (ASTFObject) child;
137                                        if ("prop".equals(fo.getClassName())) {
138                                                String id = "", name = null, type = null;
139                                                final int numChildren = fo.jjtGetNumChildren();
140                                                for (int j = 0; j < numChildren; j++) {
141                                                        final Node fochild = fo.jjtGetChild(j);
142                                                        if (fochild instanceof ASTProperty) {
143                                                                final ASTProperty prop = (ASTProperty) fochild;
144                                                                final String pname = prop.getName();
145                                                                if ("id".equalsIgnoreCase(pname)) {
146                                                                        id = prop.getValue();
147                                                                        if (id == null || id.length() == 0
148                                                                                        || !id.startsWith(elementPart)) {
149                                                                                break;
150                                                                        }
151                                                                } else if ("name".equalsIgnoreCase(pname)) {
152                                                                        name = prop.getValue();
153                                                                } else if ("type".equalsIgnoreCase(pname)) {
154                                                                        type = prop.getValue();
155                                                                }
156                                                        }
157                                                }
158                                                addExpdefCompletion(documentOffset, elementPart,
159                                                                proposals, id, name, type);
160                                        }
161                                } else if (child instanceof ASTGlobalInclude) {
162                                        processExpParamNode(child, documentOffset, elementPart,
163                                                        proposals);
164                                }
165                        }
166                }
167        }
168
169        static void addExpdefCompletion(int documentOffset, String elementPart,
170                        List<OrderableCompletionProposal> proposals, String id,
171                        String name, String type) {
172
173                if (id == null || id.length() == 0 || !id.startsWith(elementPart))
174                        return;
175                String descr = id;
176                if (type != null) {
177                        type = type.trim();
178                        final char t = type.charAt(0);
179                        final String typeName = SyntaxUtils.typeName(t);
180                        if (typeName != null)
181                                type = typeName;
182                        descr += " " + type;
183                }
184                 if (name != null)
185                 descr += " (" + name + ")";
186                final OrderableCompletionProposal prop = new OrderableCompletionProposal(
187                                id, documentOffset - elementPart.length(),
188                                elementPart.length(), id.length() - 1, null, descr, null, null);
189                prop.setName(id);
190                proposals.add(prop);
191        }
192
193        void addKeywordProposals(int documentOffset, String elementPart,
194                        List<OrderableCompletionProposal> proposals) {
195                for (String kwd : FramscriptCodeScanner.keywords) {
196                        if (kwd.startsWith(elementPart)) {
197                                OrderableCompletionProposal prop = getProposalForKeyword(kwd,
198                                                documentOffset, elementPart);
199                                proposals.add(prop);
200                        }
201                }
202        }
203
204        /**
205         * Function to customize the creation of completion proposals based on the
206         * current keyword. For example, the <code>if</code> keyword gets some
207         * additional parentheses.
208         *
209         * @param kwd
210         * @param documentOffset
211         * @param elementPart
212         * @return
213         */
214        OrderableCompletionProposal getProposalForKeyword(String kwd,
215                        int documentOffset, String elementPart) {
216                OrderableCompletionProposal prop = null;
217
218                if ("if".equals(kwd)) {
219                        String repString = kwd + " ()";
220                        prop = new OrderableCompletionProposal(repString, documentOffset
221                                        - elementPart.length(), elementPart.length(), repString
222                                        .length() - 1, null, kwd + " keyword", null, null);
223                } else {
224                        prop = new OrderableCompletionProposal(kwd, documentOffset
225                                        - elementPart.length(), elementPart.length(), kwd.length(),
226                                        null, kwd + " keyword", null, null);
227                }
228
229                prop.setName(kwd);
230                return prop;
231        }
232
233        @SuppressWarnings("unchecked")
234        private void addCompletion(Element element, int documentOffset,
235                        String elementPart, List<OrderableCompletionProposal> proposals) {
236                String name = element.getAttributeValue(SyntaxUtils.NAME_ATTRIBUTE);
237                String completion = name;
238                int cursorPosition = name.length();
239                String functionValue = element
240                                .getAttributeValue(SyntaxUtils.FUNCTION_ATTRIBUTE);
241                boolean function = (functionValue != null)
242                                && functionValue.equals("true");
243                String displayString = "";
244                IContextInformation contextInformation = null;
245                displayString = completion;
246                if (function) {
247                        completion += "()";
248                        displayString += "(";
249                        Element arguments = element.getChild(SyntaxUtils.ARGUMENTS_ELEMENT);
250                        if (arguments != null) {
251                                List<Element> argumentsList = arguments
252                                                .getChildren(SyntaxUtils.ARGUMENT_ELEMENT);
253                                for (Element argument : argumentsList) {
254                                        String attributeType = argument
255                                                        .getAttributeValue(SyntaxUtils.TYPE_ATTRIBUTE);
256                                        if ((attributeType == null)
257                                                        || (attributeType.length() == 0)) {
258                                                attributeType = "void";
259                                        }
260                                        String attributeName = argument
261                                                        .getAttributeValue(SyntaxUtils.NAME_ATTRIBUTE);
262                                        displayString += attributeType + " " + attributeName + ", ";
263                                }
264                                if (argumentsList.size() > 0) {
265                                        displayString = displayString.substring(0, displayString
266                                                        .length() - 2);
267                                }
268                        }
269                        displayString += ")";
270                        contextInformation = new ContextInformation(completion,
271                                        displayString);
272                        cursorPosition++;
273                }
274
275                String type = element.getAttributeValue(SyntaxUtils.TYPE_ATTRIBUTE);
276                if ((type != null) && (type.length() > 0)) {
277                        displayString += "  " + type;
278                }
279
280                String context = element
281                                .getAttributeValue(SyntaxUtils.CONTEXT_ATTRIBUTE);
282                if ((context != null) && (context.length() > 0)) {
283                        displayString += " (" + context + ")";
284                }
285
286                if (completion.startsWith(elementPart)) {
287                        int replacementLength = elementPart.length();
288                        int replacementOffset = documentOffset - replacementLength;
289                        OrderableCompletionProposal completionProposal = new OrderableCompletionProposal(
290                                        completion, replacementOffset, replacementLength,
291                                        cursorPosition, null, displayString, contextInformation,
292                                        null);
293                        completionProposal.setName(name);
294                        completionProposal.setFunction(function);
295                        proposals.add(completionProposal);
296                }
297        }
298
299        /*
300         * (non-Javadoc) Method declared on IContentAssistProcessor
301         */
302        public IContextInformation[] computeContextInformation(ITextViewer viewer,
303                        int documentOffset) {
304                return null;
305        }
306
307        /*
308         * (non-Javadoc) Method declared on IContentAssistProcessor
309         */
310        public char[] getCompletionProposalAutoActivationCharacters() {
311                return new char[] { '.' };
312        }
313
314        /*
315         * (non-Javadoc) Method declared on IContentAssistProcessor
316         */
317        public char[] getContextInformationAutoActivationCharacters() {
318                return new char[] {};
319        }
320
321        /*
322         * (non-Javadoc) Method declared on IContentAssistProcessor
323         */
324        public IContextInformationValidator getContextInformationValidator() {
325                return validator;
326        }
327
328        public FramclipseEditor getEditor() {
329                return editor;
330        }
331
332        /*
333         * (non-Javadoc) Method declared on IContentAssistProcessor
334         */
335        public String getErrorMessage() {
336                return null;
337        }
338
339        /**
340         * Simple content assist tip closer. The tip is valid in a range of 5
341         * characters around its popup location.
342         */
343        protected static class Validator implements IContextInformationValidator,
344                        IContextInformationPresenter {
345
346                protected int installOffset;
347
348                /*
349                 * @see IContextInformationValidator#isContextInformationValid(int)
350                 */
351                public boolean isContextInformationValid(int offset) {
352                        return Math.abs(installOffset - offset) < 5;
353                }
354
355                /*
356                 * @see IContextInformationValidator#install(IContextInformation,
357                 * ITextViewer, int)
358                 */
359                public void install(IContextInformation info, ITextViewer viewer,
360                                int offset) {
361                        installOffset = offset;
362                }
363
364                /*
365                 * @see
366                 * org.eclipse.jface.text.contentassist.IContextInformationPresenter
367                 * #updatePresentation(int, TextPresentation)
368                 */
369                public boolean updatePresentation(int documentPosition,
370                                TextPresentation presentation) {
371                        return false;
372                }
373        }
374}
Note: See TracBrowser for help on using the repository browser.