Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 51420 | Differences between
and this patch

Collapse All | Expand All

(-)schema/launchShortcuts.exsd (+7 lines)
Lines 125-130 Link Here
125
               </appInfo>
125
               </appInfo>
126
            </annotation>
126
            </annotation>
127
         </attribute>
127
         </attribute>
128
         <attribute name="nameFilter" type="string">
129
            <annotation>
130
               <documentation>
131
                  A regular expression, matched against the name of a selected resource. A match allows this launch shortcut to appear in the contextual launch popup menu for the selected resource, unless one of the filters fails in filterClass. If the filterClass is not yet loaded (lazy plugin), the result of the nameFilter test will decide inclusion in the context menu.
132
               </documentation>
133
            </annotation>
134
         </attribute>
128
      </complexType>
135
      </complexType>
129
   </element>
136
   </element>
130
137
(-)ui/org/eclipse/debug/internal/ui/actions/ContextualLaunchObjectActionDelegate.java (-5 / +17 lines)
Lines 20-25 Link Here
20
import org.eclipse.core.runtime.IPluginDescriptor;
20
import org.eclipse.core.runtime.IPluginDescriptor;
21
import org.eclipse.debug.internal.ui.DebugUIPlugin;
21
import org.eclipse.debug.internal.ui.DebugUIPlugin;
22
import org.eclipse.debug.internal.ui.Pair;
22
import org.eclipse.debug.internal.ui.Pair;
23
import org.eclipse.debug.internal.ui.StringMatcher;
23
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager;
24
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager;
24
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchShortcutExtension;
25
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchShortcutExtension;
25
import org.eclipse.debug.ui.ILaunchFilter;
26
import org.eclipse.debug.ui.ILaunchFilter;
Lines 44-53 Link Here
44
/**
45
/**
45
 * An action delegate that builds a context menu with applicable launch shortcuts.
46
 * An action delegate that builds a context menu with applicable launch shortcuts.
46
 * <p>
47
 * <p>
47
 * This class can be contributed as pop-up menu extension action. When envolked,
48
 * This class can be contributed as pop-up menu extension action. When envoked,
48
 * it becomes a sub-menu that dynamically builds a list of applicable shortcuts
49
 * it becomes a sub-menu that dynamically builds a list of applicable shortcuts
49
 * for the current selection (ISelection in the workspace). The LaunchShortCut
50
 * for the current selection (ISelection in the workspace). The LaunchShortCut
50
 * extension is consulted to obtain the list of registered short cuts. Each short
51
 * extension is consulted to obtain the list of registered shortcuts. Each short
51
 * cut may have optional information to support a context menu action. The extra
52
 * cut may have optional information to support a context menu action. The extra
52
 * information includes a "filterClass", a list of "contextLabel"s, and a list of
53
 * information includes a "filterClass", a list of "contextLabel"s, and a list of
53
 * "filter" elements. ContextLabels allow custom labels to appear for any mode
54
 * "filter" elements. ContextLabels allow custom labels to appear for any mode
Lines 205-217 Link Here
205
 	 * @return true if this shortcut should appear in the contextual launch menu
206
 	 * @return true if this shortcut should appear in the contextual launch menu
206
	 */
207
	 */
207
	private boolean isApplicable(LaunchShortcutExtension ext) {
208
	private boolean isApplicable(LaunchShortcutExtension ext) {
208
		// boolean hasMode = ext.getModes().contains(getMode(launchGroupIdentifier));
209
		String nameFilterPattern = ext.getNameFilter();
209
		// return false if there isn't a filter class or there are no filters specified by the shortcut
210
		boolean nameMatches = false;
211
		if (nameFilterPattern != null) {
212
			StringMatcher sm = new StringMatcher(nameFilterPattern, true, false);
213
			nameMatches = sm.match(fSelection.getName());
214
			if (!nameMatches) {
215
				// return now to avoid loading the filterClass
216
				return false;
217
			}
218
		}
219
210
		// Only loaded plugins will be used, so the launchFilter is null if the filterClass is not loaded
220
		// Only loaded plugins will be used, so the launchFilter is null if the filterClass is not loaded
211
		ILaunchFilter launchFilter = getFilterClassIfLoaded(ext);
221
		ILaunchFilter launchFilter = getFilterClassIfLoaded(ext);
212
		if (launchFilter == null) {
222
		if (launchFilter == null) {
213
			return false;
223
			// no launch filter available, just use nameMatches (see bug# 51420)
224
			return nameMatches;
214
		}
225
		}
226
215
		List filters = ext.getFilters();
227
		List filters = ext.getFilters();
216
		if (filters.isEmpty()) {
228
		if (filters.isEmpty()) {
217
			return false;
229
			return false;
(-)ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchShortcutExtension.java (-2 / +13 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2003 IBM Corporation and others.
2
 * Copyright (c) 2000, 2003, 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 32-38 Link Here
32
32
33
33
34
/**
34
/**
35
 * Proxy to a launch shortcut extention
35
 * Proxy to a launch shortcut extension
36
 */
36
 */
37
public class LaunchShortcutExtension implements ILaunchShortcut {
37
public class LaunchShortcutExtension implements ILaunchShortcut {
38
	
38
	
Lines 93-98 Link Here
93
	}
93
	}
94
	
94
	
95
	/**
95
	/**
96
	 * Returns the name filter of this shortcut or <code>null</code>
97
	 * 
98
	 * @return the name filter of this shortcut, or <code>null</code> if not
99
	 *  specified
100
	 */
101
	public String getNameFilter() {
102
		return getConfigurationElement().getAttribute("nameFilter"); //$NON-NLS-1$
103
	}
104
	
105
	/**
96
	 * Returns the contextual launch label of this shortcut
106
	 * Returns the contextual launch label of this shortcut
97
	 * 
107
	 * 
98
	 * @return the contextual label of this shortcut, or <code>null</code> if not
108
	 * @return the contextual label of this shortcut, or <code>null</code> if not
Lines 143-148 Link Here
143
		}
153
		}
144
		return fLaunchFilter;
154
		return fLaunchFilter;
145
	}
155
	}
156
	
146
	/**
157
	/**
147
	 * Returns all of the filter elements of this shortcut as a List of String Pairs.
158
	 * Returns all of the filter elements of this shortcut as a List of String Pairs.
148
	 * 
159
	 * 
(-)ui/org/eclipse/debug/internal/ui/StringMatcher.java (+395 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2003 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.debug.internal.ui;
12
13
 
14
import java.util.*;
15
16
/**
17
 * A string pattern matcher, suppporting * and ? wildcards.
18
 */
19
public class StringMatcher {
20
	protected String fPattern;
21
	protected int fLength; // pattern length
22
	protected boolean fIgnoreWildCards;
23
	protected boolean fIgnoreCase;
24
	protected boolean fHasLeadingStar;
25
	protected boolean fHasTrailingStar;
26
	protected String fSegments[]; //the given pattern is split into * separated segments
27
28
	/* boundary value beyond which we don't need to search in the text */
29
	protected int fBound= 0;
30
	
31
32
	protected static final char fSingleWildCard= '\u0000';
33
	
34
	public static class Position {
35
		int start; //inclusive
36
		int end; //exclusive
37
		public Position(int start, int end) {
38
			this.start= start;
39
			this.end= end;
40
		}
41
		public int getStart() {
42
			return start;
43
		}
44
		public int getEnd() {
45
			return end;
46
		}
47
	}
48
	/**
49
	 * StringMatcher constructor takes in a String object that is a simple 
50
	 * pattern which may contain ‘*’ for 0 and many characters and
51
	 * ‘?’ for exactly one character.  
52
	 *
53
	 * Literal '*' and '?' characters must be escaped in the pattern 
54
	 * e.g., "\*" means literal "*", etc.
55
	 *
56
	 * Escaping any other character (including the escape character itself), 
57
	 * just results in that character in the pattern.
58
	 * e.g., "\a" means "a" and "\\" means "\"
59
	 *
60
	 * If invoking the StringMatcher with string literals in Java, don't forget
61
	 * escape characters are represented by "\\".
62
	 *
63
	 * @param pattern the pattern to match text against
64
	 * @param ignoreCase if true, case is ignored
65
	 * @param ignoreWildCards if true, wild cards and their escape sequences are ignored
66
	 * 		  (everything is taken literally).
67
	 */
68
	public StringMatcher(String pattern, boolean ignoreCase, boolean ignoreWildCards) {
69
		if (pattern == null)
70
			throw new IllegalArgumentException();
71
		fIgnoreCase= ignoreCase;
72
		fIgnoreWildCards= ignoreWildCards;
73
		fPattern= pattern;
74
		fLength= pattern.length();
75
		
76
		if (fIgnoreWildCards) {
77
			parseNoWildCards();
78
		} else {
79
			parseWildCards();
80
		}
81
	}
82
	/**
83
	 * Find the first occurrence of the pattern between <code>start</code)(inclusive) 
84
	 * and <code>end</code>(exclusive).  
85
	 * @param <code>text</code>, the String object to search in 
86
	 * @param <code>start</code>, the starting index of the search range, inclusive
87
	 * @param <code>end</code>, the ending index of the search range, exclusive
88
	 * @return an <code>StringMatcher.Position</code> object that keeps the starting 
89
	 * (inclusive) and ending positions (exclusive) of the first occurrence of the 
90
	 * pattern in the specified range of the text; return null if not found or subtext
91
	 * is empty (start==end). A pair of zeros is returned if pattern is empty string
92
	 * Note that for pattern like "*abc*" with leading and trailing stars, position of "abc"
93
	 * is returned. For a pattern like"*??*" in text "abcdf", (1,3) is returned
94
	 */
95
	public StringMatcher.Position find(String text, int start, int end) {
96
		if (text == null)
97
			throw new IllegalArgumentException();
98
			
99
		int tlen= text.length();
100
		if (start < 0)
101
			start= 0;
102
		if (end > tlen)
103
			end= tlen;
104
		if (end < 0 ||start >= end )
105
			return null;
106
		if (fLength == 0)
107
			return new Position(start, start);
108
		if (fIgnoreWildCards) {
109
			int x= posIn(text, start, end);
110
			if (x < 0)
111
				return null;
112
			return new Position(x, x+fLength);
113
		}
114
115
		int segCount= fSegments.length;
116
		if (segCount == 0)//pattern contains only '*'(s)
117
			return new Position (start, end);
118
					
119
		int curPos= start;
120
		int matchStart= -1;
121
		int i;
122
		for (i= 0; i < segCount && curPos < end; ++i) {
123
			String current= fSegments[i];
124
			int nextMatch= regExpPosIn(text, curPos, end, current);
125
			if (nextMatch < 0 )
126
				return null;
127
			if(i == 0)
128
				matchStart= nextMatch;
129
			curPos= nextMatch + current.length();
130
		}
131
		if (i < segCount)
132
			return null;
133
		return new Position(matchStart, curPos);
134
	}
135
	/**
136
	 * match the given <code>text</code> with the pattern 
137
	 * @return true if matched eitherwise false
138
	 * @param <code>text</code>, a String object 
139
	 */
140
	public boolean match(String text) {
141
		return match(text, 0, text.length());
142
	}
143
	/**
144
	 * Given the starting (inclusive) and the ending (exclusive) positions in the   
145
	 * <code>text</code>, determine if the given substring matches with aPattern  
146
	 * @return true if the specified portion of the text matches the pattern
147
	 * @param String <code>text</code>, a String object that contains the substring to match 
148
	 * @param int <code>start<code> marks the starting position (inclusive) of the substring
149
	 * @param int <code>end<code> marks the ending index (exclusive) of the substring 
150
	 */
151
	public boolean match(String text, int start, int end) {
152
		if (null == text)
153
			throw new IllegalArgumentException();
154
155
		if (start > end)
156
			return false;
157
158
		if (fIgnoreWildCards)
159
			return (end - start == fLength) && fPattern.regionMatches(fIgnoreCase, 0, text, start, fLength);
160
		int segCount= fSegments.length;
161
		if (segCount == 0 && (fHasLeadingStar || fHasTrailingStar))  // pattern contains only '*'(s)
162
			return true;
163
		if (start == end)
164
			return fLength == 0;
165
		if (fLength == 0)
166
			return start == end;
167
168
		int tlen= text.length();
169
		if (start < 0)
170
			start= 0;
171
		if (end > tlen)
172
			end= tlen;
173
174
		int tCurPos= start;
175
		int bound= end - fBound;
176
		if ( bound < 0)
177
			return false;
178
		int i=0;
179
		String current= fSegments[i];
180
		int segLength= current.length();
181
182
		/* process first segment */
183
		if (!fHasLeadingStar){
184
			if(!regExpRegionMatches(text, start, current, 0, segLength)) {
185
				return false;
186
			} else {
187
				++i;
188
				tCurPos= tCurPos + segLength;
189
			}
190
		}
191
		if ((fSegments.length == 1) && (!fHasLeadingStar) && (!fHasTrailingStar)) {
192
			// only one segment to match, no wildcards specified
193
			return tCurPos == end;
194
		}
195
		/* process middle segments */
196
		while (i < segCount) {
197
			current= fSegments[i];
198
			int currentMatch;
199
			int k= current.indexOf(fSingleWildCard);
200
			if (k < 0) {
201
				currentMatch= textPosIn(text, tCurPos, end, current);
202
				if (currentMatch < 0)
203
					return false;
204
			} else {
205
				currentMatch= regExpPosIn(text, tCurPos, end, current);
206
				if (currentMatch < 0)
207
					return false;
208
			}
209
			tCurPos= currentMatch + current.length();
210
			i++;
211
		}
212
213
		/* process final segment */
214
		if (!fHasTrailingStar && tCurPos != end) {
215
			int clen= current.length();
216
			return regExpRegionMatches(text, end - clen, current, 0, clen);
217
		}
218
		return i == segCount ;
219
	}
220
221
	/**
222
	 * This method parses the given pattern into segments seperated by wildcard '*' characters.
223
	 * Since wildcards are not being used in this case, the pattern consists of a single segment.
224
	 */
225
	private void parseNoWildCards() {
226
		fSegments= new String[1];
227
		fSegments[0]= fPattern;
228
		fBound= fLength;
229
	}
230
	/**
231
	 * Parses the given pattern into segments seperated by wildcard '*' characters.
232
	 * @param p, a String object that is a simple regular expression with ‘*’ and/or ‘?’
233
	 */
234
	private void parseWildCards() {
235
		if(fPattern.startsWith("*"))//$NON-NLS-1$
236
			fHasLeadingStar= true;
237
		if(fPattern.endsWith("*")) {//$NON-NLS-1$
238
			/* make sure it's not an escaped wildcard */
239
			if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') {
240
				fHasTrailingStar= true;
241
			}
242
		}
243
244
		Vector temp= new Vector();
245
246
		int pos= 0;
247
		StringBuffer buf= new StringBuffer();
248
		while (pos < fLength) {
249
			char c= fPattern.charAt(pos++);
250
			switch (c) {
251
				case '\\':
252
					if (pos >= fLength) {
253
						buf.append(c);
254
					} else {
255
						char next= fPattern.charAt(pos++);
256
						/* if it's an escape sequence */
257
						if (next == '*' || next == '?' || next == '\\') {
258
							buf.append(next);
259
						} else {
260
							/* not an escape sequence, just insert literally */
261
							buf.append(c);
262
							buf.append(next);
263
						}
264
					}
265
				break;
266
				case '*':
267
					if (buf.length() > 0) {
268
						/* new segment */
269
						temp.addElement(buf.toString());
270
						fBound += buf.length();
271
						buf.setLength(0);
272
					}
273
				break;
274
				case '?':
275
					/* append special character representing single match wildcard */
276
					buf.append(fSingleWildCard);
277
				break;
278
				default:
279
					buf.append(c);
280
			}
281
		}
282
283
		/* add last buffer to segment list */
284
		if (buf.length() > 0) {
285
			temp.addElement(buf.toString());
286
			fBound += buf.length();
287
		}
288
			
289
		fSegments= new String[temp.size()];
290
		temp.copyInto(fSegments);
291
	}
292
	/** 
293
	 * @param <code>text</code>, a string which contains no wildcard
294
	 * @param <code>start</code>, the starting index in the text for search, inclusive
295
	 * @param <code>end</code>, the stopping point of search, exclusive
296
	 * @return the starting index in the text of the pattern , or -1 if not found 
297
	 */
298
	protected int posIn(String text, int start, int end) {//no wild card in pattern
299
		int max= end - fLength;
300
		
301
		if (!fIgnoreCase) {
302
			int i= text.indexOf(fPattern, start);
303
			if (i == -1 || i > max)
304
				return -1;
305
			return i;
306
		}
307
		
308
		for (int i= start; i <= max; ++i) {
309
			if (text.regionMatches(true, i, fPattern, 0, fLength))
310
				return i;
311
		}
312
		
313
		return -1;
314
	}
315
	/** 
316
	 * @param <code>text</code>, a simple regular expression that may only contain '?'(s)
317
	 * @param <code>start</code>, the starting index in the text for search, inclusive
318
	 * @param <code>end</code>, the stopping point of search, exclusive
319
	 * @param <code>p</code>, a simple regular expression that may contains '?'
320
	 * @param <code>caseIgnored</code>, wether the pattern is not casesensitive
321
	 * @return the starting index in the text of the pattern , or -1 if not found 
322
	 */
323
	protected int regExpPosIn(String text, int start, int end, String p) {
324
		int plen= p.length();
325
		
326
		int max= end - plen;
327
		for (int i= start; i <= max; ++i) {
328
			if (regExpRegionMatches(text, i, p, 0, plen))
329
				return i;
330
		}
331
		return -1;
332
	}
333
	/**
334
	 * 
335
	 * @return boolean
336
	 * @param <code>text</code>, a String to match
337
	 * @param <code>start</code>, int that indicates the starting index of match, inclusive
338
	 * @param <code>end</code> int that indicates the ending index of match, exclusive
339
	 * @param <code>p</code>, String,  String, a simple regular expression that may contain '?'
340
	 * @param <code>ignoreCase</code>, boolean indicating wether code>p</code> is case sensitive
341
	 */
342
	protected boolean regExpRegionMatches(String text, int tStart, String p, int pStart, int plen) {
343
		while (plen-- > 0) {
344
			char tchar= text.charAt(tStart++);
345
			char pchar= p.charAt(pStart++);
346
347
			/* process wild cards */
348
			if (!fIgnoreWildCards) {
349
				/* skip single wild cards */
350
				if (pchar == fSingleWildCard) {
351
					continue;
352
				}
353
			}
354
			if (pchar == tchar)
355
				continue;
356
			if (fIgnoreCase) {
357
				if (Character.toUpperCase(tchar) == Character.toUpperCase(pchar))
358
					continue;
359
				// comparing after converting to upper case doesn't handle all cases;
360
				// also compare after converting to lower case
361
				if (Character.toLowerCase(tchar) == Character.toLowerCase(pchar))
362
					continue;
363
			}
364
			return false;
365
		}
366
		return true;
367
	}
368
	/** 
369
	 * @param <code>text</code>, the string to match
370
	 * @param <code>start</code>, the starting index in the text for search, inclusive
371
	 * @param <code>end</code>, the stopping point of search, exclusive
372
	 * @param code>p</code>, a string that has no wildcard
373
	 * @param <code>ignoreCase</code>, boolean indicating wether code>p</code> is case sensitive
374
	 * @return the starting index in the text of the pattern , or -1 if not found 
375
	 */
376
	protected int textPosIn(String text, int start, int end, String p) { 
377
		
378
		int plen= p.length();
379
		int max= end - plen;
380
		
381
		if (!fIgnoreCase) {
382
			int i= text.indexOf(p, start);
383
			if (i == -1 || i > max)
384
				return -1;
385
			return i;
386
		}
387
		
388
		for (int i= start; i <= max; ++i) {
389
			if (text.regionMatches(true, i, p, 0, plen))
390
				return i;
391
		}
392
		
393
		return -1;
394
	}
395
}

Return to bug 51420