Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

summaryrefslogtreecommitdiffstats
blob: fe6a3dfe21912d563f9b0073b77b40fe411b2df5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package org.eclipse.jst.jsp.ui.internal.contentassist;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
import org.eclipse.jdt.ui.text.java.CompletionProposalComparator;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jst.jsp.core.internal.java.JSPTranslation;
import org.eclipse.swt.graphics.Image;

/**
 * Passed into ICodeComplete#codeComplete(int offset, CompletionRequestor requestor).
 * Adapts IJavaCompletionProposals to JSPCompletion proposals.
 * This includes:
 *  - translating offsets
 *  - "fixing" up display strings
 *  - filtering some unwanted proposals
 *
 * @plannedfor 1.0
 */
public class JSPProposalCollector extends CompletionProposalCollector {

	private JSPTranslation fTranslation;
	private Comparator fComparator;
	
	public JSPProposalCollector(ICompilationUnit cu, JSPTranslation translation) {
		super(cu);
	
		if(translation == null)
			throw new IllegalArgumentException("JSPTranslation cannot be null"); //$NON-NLS-1$
		
		fTranslation = translation;
	}

	/**
	 * Ensures that we only return JSPCompletionProposals.
	 * @return an array of JSPCompletionProposals
	 */
	public JSPCompletionProposal[] getJSPCompletionProposals() {
		List results = new ArrayList();
		IJavaCompletionProposal[] javaProposals = getJavaCompletionProposals();
		// need to filter out non JSPCompletionProposals
		// because their offsets haven't been translated
		for (int i = 0; i < javaProposals.length; i++) {
			if(javaProposals[i] instanceof JSPCompletionProposal)
				results.add(javaProposals[i]);
		}
		Collections.sort(results, getComparator());
		return (JSPCompletionProposal[])results.toArray(new JSPCompletionProposal[results.size()]);
	}
	
	private Comparator getComparator() {
		if(fComparator == null)
			fComparator = new CompletionProposalComparator();
		return fComparator;
	}
	
	/**
	 * Overridden to:
	 *  - translate Java -> JSP offsets
	 *  - fix cursor-position-after
	 *  - fix mangled servlet name in display string
	 *  - remove unwanted proposals (servlet constructor)
	 */
	protected IJavaCompletionProposal createJavaCompletionProposal(CompletionProposal proposal) {
		
		JSPCompletionProposal jspProposal = null;
		
		// ignore constructor proposals (they're not relevant for our JSP proposal list)
		if(!proposal.isConstructor()) {
			
			if(proposal.getKind() == CompletionProposal.TYPE_REF) {
				String signature = String.valueOf(proposal.getDeclarationSignature());
				String completion = String.valueOf(proposal.getCompletion());
				if(completion.indexOf(signature) != -1) {
					jspProposal = createAutoImportProposal(proposal);			
				}
			}
			
			// default behavior
			if(jspProposal == null)
				jspProposal = createJspProposal(proposal);		
		}
		return jspProposal;
	}

	
	
	private JSPCompletionProposal createAutoImportProposal(CompletionProposal proposal) {
		
		JSPCompletionProposal jspProposal = null;

		String signature = new String(proposal.getDeclarationSignature());
		String completion = new String(proposal.getCompletion());
		
		// it's fully qualified so we should
		// add an import statement
		// create an autoimport proposal
		String newCompletion = completion.replaceAll(signature + ".", ""); //$NON-NLS-1$ //$NON-NLS-2$
		
		// java offset
		int offset = proposal.getReplaceStart();
		// replacement length
		int length = proposal.getReplaceEnd() - offset;
		// translate offset from Java > JSP
		offset = fTranslation.getJspOffset(offset);
		// cursor position after must be calculated
		int positionAfter = calculatePositionAfter(proposal, newCompletion, offset);
		
		// from java proposal
		IJavaCompletionProposal javaProposal = super.createJavaCompletionProposal(proposal);
		proposal.getDeclarationSignature();
		Image image = javaProposal.getImage();
		String displayString = javaProposal.getDisplayString();
		displayString = getTranslation().fixupMangledName(displayString);
		IContextInformation contextInformation = javaProposal.getContextInformation();
		// don't do this, it's slow
		// String additionalInfo = javaProposal.getAdditionalProposalInfo();
		int relevance = javaProposal.getRelevance();
		
		boolean updateLengthOnValidate = true;
		
		jspProposal = new AutoImportProposal(completion, newCompletion, offset, length, positionAfter, image, displayString, contextInformation, null, relevance, updateLengthOnValidate);
		
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=124483
		// set wrapped java proposal so additional info can be calculated on demand
		jspProposal.setJavaCompletionProposal(javaProposal);
		
		return jspProposal;
	}

	private JSPCompletionProposal createJspProposal(CompletionProposal proposal) {
		
		JSPCompletionProposal jspProposal;
		String completion = String.valueOf(proposal.getCompletion());
		// java offset
		int offset = proposal.getReplaceStart();
		// replacement length
		int length = proposal.getReplaceEnd() - offset;
		// translate offset from Java > JSP
		offset = fTranslation.getJspOffset(offset);
		// cursor position after must be calculated
		int positionAfter = calculatePositionAfter(proposal, completion, offset);
		
		// from java proposal
		IJavaCompletionProposal javaProposal = super.createJavaCompletionProposal(proposal);
		proposal.getDeclarationSignature();
		Image image = javaProposal.getImage();
		String displayString = javaProposal.getDisplayString();
		displayString = getTranslation().fixupMangledName(displayString);
		IContextInformation contextInformation = javaProposal.getContextInformation();
		// String additionalInfo = javaProposal.getAdditionalProposalInfo();
		int relevance = javaProposal.getRelevance();
		
		boolean updateLengthOnValidate = true;
		
		jspProposal = new JSPCompletionProposal(completion, offset, length, positionAfter, image, displayString, contextInformation, null, relevance, updateLengthOnValidate);
		
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=124483
		// set wrapped java proposal so additional info can be calculated on demand
		jspProposal.setJavaCompletionProposal(javaProposal);
		
		return jspProposal;
	}

	/**
	 * Cacluates the where the cursor should be after applying this proposal.
	 * eg. method(|) if the method proposal chosen had params.
	 * 
	 * @param proposal
	 * @param completion
	 * @param currentCursorOffset
	 * @return
	 */
	private int calculatePositionAfter(CompletionProposal proposal, String completion, int currentCursorOffset) {
		// calculate cursor position after
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=118398
		//int positionAfter = currentCursorOffset+completion.length();
		int positionAfter = completion.length();
		
		int kind = proposal.getKind();
		
		// may need better logic here...
		// put cursor inside parenthesis if there's params
		// only checking for any kind of declaration
		if(kind == CompletionProposal.ANONYMOUS_CLASS_DECLARATION || kind == CompletionProposal.METHOD_DECLARATION || kind == CompletionProposal.POTENTIAL_METHOD_DECLARATION || kind == CompletionProposal.METHOD_REF) {
			String[] params = Signature.getParameterTypes(String.valueOf(proposal.getSignature()));
			if(completion.length() > 0 && params.length > 0)
				positionAfter--;
		}
		return positionAfter;
	}
	
	static char[] getTypeTriggers() {
		return TYPE_TRIGGERS;
	}

	public JSPTranslation getTranslation() {
		return fTranslation;
	}
	
}

Back to the top