1313 *******************************************************************************/
1414package org .eclipse .jdt .internal .ui .javaeditor ;
1515
16+ import java .util .HashMap ;
1617import java .util .LinkedList ;
1718import java .util .List ;
19+ import java .util .Map ;
1820import java .util .regex .Matcher ;
1921import java .util .regex .Pattern ;
2022
2123import org .eclipse .swt .custom .StyledText ;
2224
25+ import org .eclipse .jface .text .AbstractDocument ;
26+ import org .eclipse .jface .text .IDocument ;
2327import org .eclipse .jface .text .ITextViewerExtension5 ;
2428import org .eclipse .jface .text .source .ISourceViewer ;
2529
@@ -68,9 +72,13 @@ public class JavaStickyLinesProvider implements IStickyLinesProvider {
6872 private final static Pattern ELSE_PATTERN = Pattern .compile ("else[\\ s,{]" ); //$NON-NLS-1$
6973 private final static Pattern DO_PATTERN = Pattern .compile ("do[\\ s,{]" ); //$NON-NLS-1$
7074 private final static Pattern WHILE_PATTERN = Pattern .compile ("while[\\ s,{]" ); //$NON-NLS-1$
75+ private final static Pattern FOR_PATTERN = Pattern .compile ("for[\\ s,{]" ); //$NON-NLS-1$
7176 private final static Pattern TRY_PATTERN = Pattern .compile ("try[\\ s,{]" ); //$NON-NLS-1$
7277 private final static Pattern NEW_PATTERN = Pattern .compile ("new[\\ s,{]" ); //$NON-NLS-1$
7378
79+ private static Map <ITypeRoot , CompilationUnit > cuMap = new HashMap <>();
80+ private static Map <ITypeRoot , Long > timeMap = new HashMap <>();
81+
7482 @ Override
7583 public List <IStickyLine > getStickyLines (ISourceViewer sourceViewer , int lineNumber , StickyLinesProperties properties ) {
7684 final LinkedList <IStickyLine > stickyLines = new LinkedList <>();
@@ -96,163 +104,182 @@ public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumb
96104
97105 if (textWidgetLineNumber > 0 ) {
98106 ITypeRoot typeRoot = getJavaInput (javaEditor );
99-
100107 ASTNode node = null ;
101108 if (typeRoot != null ) {
102109 WorkingCopyOwner workingCopyOwner = new WorkingCopyOwner () {
103110 };
111+ CompilationUnit cu = cuMap .get (typeRoot );
112+ IDocument document = sourceViewer .getDocument ();
113+ long currTime = getDocumentTimestamp (document );
114+ if (cu != null && !typeRoot .isReadOnly ()) {
115+ Long oldTime = timeMap .get (typeRoot );
116+ if (oldTime == null || currTime != oldTime .longValue ()) {
117+ cu = null ;
118+ }
119+ }
104120 try {
105- unit = typeRoot .getWorkingCopy (workingCopyOwner , null );
106- if (unit != null ) {
107- CompilationUnit cu = convertICompilationUnitToCompilationUnit (unit );
108- node = getASTNode (cu , mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber )+1 , line );
109- while (node == null && textWidgetLineNumber > 0 ) {
121+ if (cu == null ) {
122+ unit = typeRoot .getWorkingCopy (workingCopyOwner , null );
123+ if (unit != null ) {
124+ cu = convertICompilationUnitToCompilationUnit (unit );
125+ }
126+ }
127+ if (cu == null ) {
128+ return stickyLines ;
129+ }
130+ cuMap .put (typeRoot , cu );
131+ timeMap .put (typeRoot , Long .valueOf (currTime ));
132+ node = getASTNode (cu , mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber )+1 , line );
133+ while (node == null && textWidgetLineNumber > 0 ) {
134+ line = textWidget .getLine (--textWidgetLineNumber );
135+ startIndentation = getIndentation (line );
136+ while (startIndentation == IGNORE_LINE_INDENTATION && textWidgetLineNumber > 0 ) {
110137 line = textWidget .getLine (--textWidgetLineNumber );
111138 startIndentation = getIndentation (line );
112- while (startIndentation == IGNORE_LINE_INDENTATION && textWidgetLineNumber > 0 ) {
113- line = textWidget .getLine (--textWidgetLineNumber );
114- startIndentation = getIndentation (line );
115- }
116- if (textWidgetLineNumber > 0 ) {
117- int position = cu .getPosition (mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber ) + 1 , startIndentation );
118- if (position >= 0 ) {
119- node = getASTNode (cu , mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber )+1 , line );
120- }
139+ }
140+ if (textWidgetLineNumber > 0 ) {
141+ int position = cu .getPosition (mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber ) + 1 , startIndentation );
142+ if (position >= 0 ) {
143+ node = getASTNode (cu , mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber )+1 , line );
121144 }
122145 }
123- if (node != null ) {
124- boolean addStickyLine = false ;
125- int nodeLineNumber = 0 ;
126- while (node != null ) {
127- addStickyLine = false ;
128- switch (node .getNodeType ()) {
129- case ASTNode .ANNOTATION_TYPE_DECLARATION :
130- case ASTNode .TYPE_DECLARATION :
131- case ASTNode .ENUM_DECLARATION :
132- addStickyLine = true ;
133- ASTNode name = ((AbstractTypeDeclaration )node ).getName ();
134- nodeLineNumber = cu .getLineNumber (name .getStartPosition ());
135- break ;
136- case ASTNode .TYPE_DECLARATION_STATEMENT :
137- addStickyLine = true ;
138- ASTNode typeDeclStmtName = ((TypeDeclarationStatement )node ).getDeclaration ().getName ();
139- nodeLineNumber = cu .getLineNumber (typeDeclStmtName .getStartPosition ());
140- break ;
141- case ASTNode .METHOD_DECLARATION :
142- addStickyLine = true ;
143- ASTNode methodName = ((MethodDeclaration )node ).getName ();
144- nodeLineNumber = cu .getLineNumber (methodName .getStartPosition ());
145- break ;
146- case ASTNode .RECORD_DECLARATION :
147- addStickyLine = true ;
148- ASTNode recordName = ((RecordDeclaration )node ).getName ();
149- nodeLineNumber = cu .getLineNumber (recordName .getStartPosition ());
150- break ;
151- case ASTNode .MODULE_DECLARATION :
152- addStickyLine = true ;
153- ASTNode moduleName = ((ModuleDeclaration )node ).getName ();
154- nodeLineNumber = cu .getLineNumber (moduleName .getStartPosition ());
155- break ;
156- case ASTNode .LAMBDA_EXPRESSION :
157- addStickyLine = true ;
158- ASTNode lambdaBody = ((LambdaExpression )node ).getBody ();
159- nodeLineNumber = cu .getLineNumber (lambdaBody .getStartPosition ());
160- break ;
161- case ASTNode .IF_STATEMENT :
162- addStickyLine = true ;
163- IfStatement ifStmt = (IfStatement )node ;
164- ASTNode ifExpression = ifStmt .getExpression ();
165- nodeLineNumber = cu .getLineNumber (ifExpression .getStartPosition ());
166- Statement elseStmt = ifStmt .getElseStatement ();
167- if (elseStmt != null ) {
168- int elseLine = cu .getLineNumber (elseStmt .getStartPosition ());
169- if (elseLine <= mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber + 1 )) {
170- Pattern p = ELSE_PATTERN ;
171- nodeLineNumber = elseLine ;
172- String stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
173- Matcher m = p .matcher (stmtLine );
174- while (!m .find () && nodeLineNumber > 1 ) {
175- nodeLineNumber --;
176- stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
177- m = p .matcher (stmtLine );
178- }
179- node = node .getParent ();
146+ }
147+ if (node != null ) {
148+ boolean addStickyLine = false ;
149+ int nodeLineNumber = 0 ;
150+ while (node != null ) {
151+ addStickyLine = false ;
152+ switch (node .getNodeType ()) {
153+ case ASTNode .ANNOTATION_TYPE_DECLARATION :
154+ case ASTNode .TYPE_DECLARATION :
155+ case ASTNode .ENUM_DECLARATION :
156+ addStickyLine = true ;
157+ ASTNode name = ((AbstractTypeDeclaration )node ).getName ();
158+ nodeLineNumber = cu .getLineNumber (name .getStartPosition ());
159+ break ;
160+ case ASTNode .TYPE_DECLARATION_STATEMENT :
161+ addStickyLine = true ;
162+ ASTNode typeDeclStmtName = ((TypeDeclarationStatement )node ).getDeclaration ().getName ();
163+ nodeLineNumber = cu .getLineNumber (typeDeclStmtName .getStartPosition ());
164+ break ;
165+ case ASTNode .METHOD_DECLARATION :
166+ addStickyLine = true ;
167+ ASTNode methodName = ((MethodDeclaration )node ).getName ();
168+ nodeLineNumber = cu .getLineNumber (methodName .getStartPosition ());
169+ break ;
170+ case ASTNode .RECORD_DECLARATION :
171+ addStickyLine = true ;
172+ ASTNode recordName = ((RecordDeclaration )node ).getName ();
173+ nodeLineNumber = cu .getLineNumber (recordName .getStartPosition ());
174+ break ;
175+ case ASTNode .MODULE_DECLARATION :
176+ addStickyLine = true ;
177+ ASTNode moduleName = ((ModuleDeclaration )node ).getName ();
178+ nodeLineNumber = cu .getLineNumber (moduleName .getStartPosition ());
179+ break ;
180+ case ASTNode .LAMBDA_EXPRESSION :
181+ addStickyLine = true ;
182+ ASTNode lambdaBody = ((LambdaExpression )node ).getBody ();
183+ nodeLineNumber = cu .getLineNumber (lambdaBody .getStartPosition ());
184+ break ;
185+ case ASTNode .IF_STATEMENT :
186+ addStickyLine = true ;
187+ IfStatement ifStmt = (IfStatement )node ;
188+ ASTNode ifExpression = ifStmt .getExpression ();
189+ nodeLineNumber = cu .getLineNumber (ifExpression .getStartPosition ());
190+ Statement elseStmt = ifStmt .getElseStatement ();
191+ if (elseStmt != null ) {
192+ int elseLine = cu .getLineNumber (elseStmt .getStartPosition ());
193+ if (elseLine <= mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber + 1 )) {
194+ Pattern p = ELSE_PATTERN ;
195+ nodeLineNumber = elseLine ;
196+ String stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
197+ Matcher m = p .matcher (stmtLine );
198+ while (!m .find () && nodeLineNumber > 1 ) {
199+ nodeLineNumber --;
200+ stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
201+ m = p .matcher (stmtLine );
180202 }
181- }
182- while (node .getLocationInParent () == IfStatement .ELSE_STATEMENT_PROPERTY ) {
183203 node = node .getParent ();
184204 }
185- break ;
186- case ASTNode .FOR_STATEMENT :
187- addStickyLine = true ;
188- ASTNode forExpression = ((ForStatement )node ).getExpression ();
189- nodeLineNumber = cu .getLineNumber (forExpression .getStartPosition ());
190- break ;
191- case ASTNode .ENHANCED_FOR_STATEMENT :
192- addStickyLine = true ;
193- ASTNode enhancedForExpression = ((EnhancedForStatement )node ).getExpression ();
194- nodeLineNumber = cu .getLineNumber (enhancedForExpression .getStartPosition ());
195- break ;
196- case ASTNode .SWITCH_EXPRESSION :
197- addStickyLine = true ;
198- ASTNode switchExpExpression = ((SwitchExpression )node ).getExpression ();
199- nodeLineNumber = cu .getLineNumber (switchExpExpression .getStartPosition ());
200- break ;
201- case ASTNode .SWITCH_STATEMENT :
202- addStickyLine = true ;
203- ASTNode switchStmtExpression = ((SwitchStatement )node ).getExpression ();
204- nodeLineNumber = cu .getLineNumber (switchStmtExpression .getStartPosition ());
205- break ;
206- case ASTNode .WHILE_STATEMENT :
207- case ASTNode .DO_STATEMENT :
208- case ASTNode .TRY_STATEMENT :
209- case ASTNode .ANONYMOUS_CLASS_DECLARATION :
210- addStickyLine = true ;
211- ASTNode bodyProperty = null ;
212- Pattern pattern = null ;
213- if (node .getNodeType () == ASTNode .DO_STATEMENT ) {
205+ }
206+ while (node .getLocationInParent () == IfStatement .ELSE_STATEMENT_PROPERTY ) {
207+ node = node .getParent ();
208+ }
209+ break ;
210+ case ASTNode .ENHANCED_FOR_STATEMENT :
211+ addStickyLine = true ;
212+ ASTNode enhancedForExpression = ((EnhancedForStatement )node ).getExpression ();
213+ nodeLineNumber = cu .getLineNumber (enhancedForExpression .getStartPosition ());
214+ break ;
215+ case ASTNode .SWITCH_EXPRESSION :
216+ addStickyLine = true ;
217+ ASTNode switchExpExpression = ((SwitchExpression )node ).getExpression ();
218+ nodeLineNumber = cu .getLineNumber (switchExpExpression .getStartPosition ());
219+ break ;
220+ case ASTNode .SWITCH_STATEMENT :
221+ addStickyLine = true ;
222+ ASTNode switchStmtExpression = ((SwitchStatement )node ).getExpression ();
223+ nodeLineNumber = cu .getLineNumber (switchStmtExpression .getStartPosition ());
224+ break ;
225+ case ASTNode .WHILE_STATEMENT :
226+ case ASTNode .DO_STATEMENT :
227+ case ASTNode .TRY_STATEMENT :
228+ case ASTNode .FOR_STATEMENT :
229+ case ASTNode .ANONYMOUS_CLASS_DECLARATION :
230+ addStickyLine = true ;
231+ ASTNode bodyProperty = null ;
232+ Pattern pattern = null ;
233+ switch (node .getNodeType ()) {
234+ case ASTNode .DO_STATEMENT :
214235 bodyProperty = ((DoStatement )node ).getBody ();
215236 pattern = DO_PATTERN ;
216- } else if (node .getNodeType () == ASTNode .WHILE_STATEMENT ) {
237+ break ;
238+ case ASTNode .FOR_STATEMENT :
239+ bodyProperty = ((ForStatement )node ).getBody ();
240+ pattern = FOR_PATTERN ;
241+ break ;
242+ case ASTNode .WHILE_STATEMENT :
217243 bodyProperty = ((WhileStatement )node ).getBody ();
218244 pattern = WHILE_PATTERN ;
219- } else if (node .getNodeType () == ASTNode .TRY_STATEMENT ) {
245+ break ;
246+ case ASTNode .TRY_STATEMENT :
220247 bodyProperty = ((TryStatement )node ).getBody ();
221248 pattern = TRY_PATTERN ;
222- } else if (node .getNodeType () == ASTNode .ANONYMOUS_CLASS_DECLARATION ) {
249+ break ;
250+ case ASTNode .ANONYMOUS_CLASS_DECLARATION :
223251 bodyProperty = (ASTNode ) ((AnonymousClassDeclaration )node ).bodyDeclarations ().get (0 );
224252 pattern = NEW_PATTERN ;
253+ break ;
254+ }
255+ if (bodyProperty != null && pattern != null ) {
256+ nodeLineNumber = cu .getLineNumber (bodyProperty .getStartPosition ());
257+ String stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
258+ Matcher m = pattern .matcher (stmtLine );
259+ while (!m .find () && nodeLineNumber > 1 ) {
260+ nodeLineNumber --;
261+ stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
262+ m = pattern .matcher (stmtLine );
225263 }
226- if (bodyProperty != null && pattern != null ) {
227- nodeLineNumber = cu .getLineNumber (bodyProperty .getStartPosition ());
228- String stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
229- Matcher m = pattern .matcher (stmtLine );
230- while (!m .find () && nodeLineNumber > 1 ) {
231- nodeLineNumber --;
232- stmtLine = textWidget .getLine (mapLineNumberToWidget (sourceViewer , nodeLineNumber - 1 ));
233- m = pattern .matcher (stmtLine );
234- }
235- }
236- break ;
237- case ASTNode .SWITCH_CASE :
238- case ASTNode .CASE_DEFAULT_EXPRESSION :
239- case ASTNode .CATCH_CLAUSE :
240- addStickyLine = true ;
241- nodeLineNumber = cu .getLineNumber (node .getStartPosition ());
242- break ;
243- default :
244- break ;
245- }
246- if (addStickyLine && nodeLineNumber <= lineNumber ) {
247- stickyLines .addFirst (new StickyLine (nodeLineNumber - 1 , sourceViewer ));
248- }
249- if (node .getNodeType () == ASTNode .MODIFIER ) {
250- Modifier modifier = (Modifier )node ;
251- startIndentation += modifier .getLength ();
252- node = getASTNode (cu , mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber +1 ), line );
253- } else {
254- node = node .getParent ();
255- }
264+ }
265+ break ;
266+ case ASTNode .SWITCH_CASE :
267+ case ASTNode .CASE_DEFAULT_EXPRESSION :
268+ case ASTNode .CATCH_CLAUSE :
269+ nodeLineNumber = cu .getLineNumber (node .getStartPosition ());
270+ break ;
271+ default :
272+ break ;
273+ }
274+ if (addStickyLine && nodeLineNumber <= lineNumber ) {
275+ stickyLines .addFirst (new StickyLine (nodeLineNumber - 1 , sourceViewer ));
276+ }
277+ if (node .getNodeType () == ASTNode .MODIFIER ) {
278+ Modifier modifier = (Modifier )node ;
279+ startIndentation += modifier .getLength ();
280+ node = getASTNode (cu , mapWidgetToLineNumber (sourceViewer , textWidgetLineNumber +1 ), line );
281+ } else {
282+ node = node .getParent ();
256283 }
257284 }
258285 }
@@ -267,6 +294,13 @@ public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumb
267294 return stickyLines ;
268295 }
269296
297+ private long getDocumentTimestamp (IDocument document ) {
298+ if (document instanceof AbstractDocument ad ) {
299+ return ad .getModificationStamp ();
300+ }
301+ return 0 ;
302+ }
303+
270304 private ASTNode getASTNode (CompilationUnit cu , int lineNum , String line ) {
271305 int linePos = cu .getPosition (lineNum , 0 );
272306 if (linePos >= 0 ) {
0 commit comments