2
2
3
3
import com .intellij .openapi .application .ApplicationManager ;
4
4
import com .intellij .openapi .command .CommandProcessor ;
5
- import com .intellij .openapi .diagnostic .Logger ;
6
5
import com .intellij .openapi .editor .Document ;
7
6
import com .intellij .openapi .fileTypes .FileType ;
8
7
import com .intellij .openapi .util .Pair ;
9
8
import com .intellij .openapi .util .TextRange ;
10
9
import com .intellij .psi .*;
11
- import com .intellij .psi .impl .source .tree .LeafPsiElement ;
12
10
import com .intellij .psi .util .PsiTreeUtil ;
13
11
import com .intellij .util .DocumentUtil ;
14
12
import net .seesharpsoft .intellij .plugins .csv .CsvHelper ;
26
24
27
25
public class CsvPsiTreeUpdater implements PsiFileHolder , Suspendable {
28
26
29
- private final static Logger LOG = Logger . getInstance ( CsvPsiTreeUpdater . class );
27
+ protected final EventListenerList myEventListenerList = new EventListenerList ( );
30
28
31
29
private final PsiFileHolder myPsiFileHolder ;
32
30
33
- private final PsiFileFactory myFileFactory ;
34
-
35
- private final CsvPsiParserFileType myFileType ;
31
+ private PsiFileFactory myFileFactory ;
36
32
37
- protected final EventListenerList myEventListenerList = new EventListenerList () ;
33
+ private CsvPsiParserFileType myFileType ;
38
34
39
35
private List <PsiAction > myUncommittedActions = new ArrayList <>();
40
36
41
37
public CsvPsiTreeUpdater (@ NotNull PsiFileHolder psiFileHolder ) {
42
38
myPsiFileHolder = psiFileHolder ;
43
- myFileFactory = PsiFileFactory .getInstance (getPsiFile ().getProject ());
44
- myFileType = new CsvPsiParserFileType (CsvHelper .getValueSeparator (psiFileHolder .getPsiFile ()), CsvHelper .getEscapeCharacter (psiFileHolder .getPsiFile ()));
45
39
}
46
40
47
41
private FileType getFileType () {
48
- myFileType .setSeparator (CsvHelper .getValueSeparator (getPsiFile ()));
49
- myFileType .setEscapeCharacter (CsvHelper .getEscapeCharacter (getPsiFile ()));
42
+ PsiFile psiFile = getPsiFile ();
43
+ if (psiFile == null ) return null ;
44
+
45
+ if (myFileType == null ) {
46
+ myFileType = new CsvPsiParserFileType (CsvHelper .getValueSeparator (psiFile ), CsvHelper .getEscapeCharacter (psiFile ));
47
+ } else {
48
+ myFileType .setSeparator (CsvHelper .getValueSeparator (psiFile ));
49
+ myFileType .setEscapeCharacter (CsvHelper .getEscapeCharacter (psiFile ));
50
+ }
50
51
return myFileType ;
51
52
}
52
53
54
+ private PsiFileFactory getFileFactory () {
55
+ PsiFile psiFile = getPsiFile ();
56
+ if (psiFile == null ) return null ;
57
+
58
+ if (myFileFactory == null ) {
59
+ myFileFactory = PsiFileFactory .getInstance (getPsiFile ().getProject ());
60
+ }
61
+ return myFileFactory ;
62
+ }
63
+
53
64
private PsiFile createFile (@ NotNull String text ) {
54
- return myFileFactory .createFileFromText ("a.csv" , getFileType (), text );
65
+ PsiFileFactory fileFactory = getFileFactory ();
66
+ return fileFactory == null ? null : getFileFactory ().createFileFromText ("a.csv" , getFileType (), text );
55
67
}
56
68
57
69
private boolean isIndicatingComment (@ NotNull String text ) {
58
70
return text .trim ().startsWith (CsvEditorSettings .getInstance ().getCommentIndicator ());
59
71
}
60
72
61
- public @ NotNull CsvField createField (@ NotNull String text , boolean enquoteCommentIndicator ) {
73
+ public @ Nullable CsvField createField (@ NotNull String text , boolean enquoteCommentIndicator ) {
62
74
boolean enforceQuoting = CsvEditorSettings .getInstance ().isQuotingEnforced ();
63
75
if (enquoteCommentIndicator && isIndicatingComment (text )) enforceQuoting = true ;
64
76
65
77
String sanitizedValue = CsvHelper .quoteCsvField (text , CsvHelper .getEscapeCharacter (getPsiFile ()), CsvHelper .getValueSeparator (getPsiFile ()), enforceQuoting );
66
78
67
- CsvField field = SyntaxTraverser .psiTraverser (createFile (sanitizedValue )).filter (CsvField .class ).first ();
68
- if (field == null ) {
69
- LOG .warn (
70
- CsvHelper .formatString ("Couldn't create field for text: ${sanitizedValue}" ,
71
- Collections .singletonMap ("sanitizedValue" , sanitizedValue ))
72
- );
73
- field = (CsvField ) CsvTypes .Factory .createElement (new LeafPsiElement (CsvTypes .FIELD , "" ));
74
- }
75
- return field ;
79
+ return SyntaxTraverser .psiTraverser (createFile (sanitizedValue )).filter (CsvField .class ).first ();
76
80
}
77
81
78
- public @ NotNull CsvRecord createRecord () {
82
+ public @ Nullable CsvRecord createRecord () {
79
83
return SyntaxTraverser .psiTraverser (createFile ("\n " )).filter (CsvRecord .class ).first ();
80
84
}
81
85
@@ -85,6 +89,8 @@ private boolean isIndicatingComment(@NotNull String text) {
85
89
86
90
public Document getDocument () {
87
91
PsiFile psiFile = getPsiFile ();
92
+ if (psiFile == null ) return null ;
93
+
88
94
return PsiDocumentManager .getInstance (psiFile .getProject ()).getDocument (psiFile );
89
95
}
90
96
@@ -332,6 +338,7 @@ public synchronized void commit() {
332
338
333
339
suspend ();
334
340
List <PsiAction > actionsToCommit = new ArrayList <>(myUncommittedActions );
341
+ myUncommittedActions .clear ();
335
342
if (!doCommit (() -> {
336
343
try {
337
344
actionsToCommit .forEach (PsiAction ::execute );
@@ -341,16 +348,15 @@ public synchronized void commit() {
341
348
}
342
349
})) {
343
350
resume ();
344
- } else {
345
- myUncommittedActions .clear ();
346
351
}
347
352
}
348
353
349
354
private boolean doCommit (@ NotNull Runnable runnable ) {
350
- if (!getPsiFile ().isWritable ()) return false ;
351
-
355
+ PsiFile psiFile = getPsiFile ();
352
356
Document document = getDocument ();
353
357
358
+ if (psiFile == null || !psiFile .isWritable () || document == null || !document .isWritable ()) return false ;
359
+
354
360
ApplicationManager .getApplication ().runWriteAction (() -> {
355
361
CommandProcessor .getInstance ().executeCommand (
356
362
getPsiFile ().getProject (),
@@ -406,18 +412,20 @@ private static class AddSiblingPsiAction extends PsiAction {
406
412
private final PsiElement myElementToAdd ;
407
413
private final boolean myBefore ;
408
414
409
- AddSiblingPsiAction (@ NotNull PsiElement anchor , @ NotNull PsiElement elementToAdd ) {
415
+ AddSiblingPsiAction (@ NotNull PsiElement anchor , @ Nullable PsiElement elementToAdd ) {
410
416
this (anchor , elementToAdd , false );
411
417
}
412
418
413
- AddSiblingPsiAction (@ NotNull PsiElement anchor , @ NotNull PsiElement elementToAdd , boolean before ) {
419
+ AddSiblingPsiAction (@ NotNull PsiElement anchor , @ Nullable PsiElement elementToAdd , boolean before ) {
414
420
super (anchor );
415
421
myElementToAdd = elementToAdd ;
416
422
myBefore = before ;
417
423
}
418
424
419
425
@ Override
420
426
public void execute () {
427
+ if (myElementToAdd == null ) return ;
428
+
421
429
PsiElement anchor = getAnchor ();
422
430
if (anchor .getParent () == null ) return ;
423
431
if (myBefore ) {
@@ -432,13 +440,15 @@ private static class AddChildPsiAction extends PsiAction {
432
440
433
441
private final PsiElement myElementToAdd ;
434
442
435
- AddChildPsiAction (@ NotNull PsiElement parent , @ NotNull PsiElement elementToAdd ) {
443
+ AddChildPsiAction (@ NotNull PsiElement parent , @ Nullable PsiElement elementToAdd ) {
436
444
super (parent );
437
445
myElementToAdd = elementToAdd ;
438
446
}
439
447
440
448
@ Override
441
449
public void execute () {
450
+ if (myElementToAdd == null ) return ;
451
+
442
452
PsiElement anchor = getAnchor ();
443
453
anchor .add (myElementToAdd );
444
454
}
@@ -448,13 +458,15 @@ private static class ReplacePsiAction extends PsiAction {
448
458
449
459
private final PsiElement myReplacement ;
450
460
451
- ReplacePsiAction (@ NotNull PsiElement anchor , @ NotNull PsiElement replacement ) {
461
+ ReplacePsiAction (@ NotNull PsiElement anchor , @ Nullable PsiElement replacement ) {
452
462
super (anchor );
453
463
myReplacement = replacement ;
454
464
}
455
465
456
466
@ Override
457
467
public void execute () {
468
+ if (myReplacement == null ) return ;
469
+
458
470
getAnchor ().replace (myReplacement );
459
471
}
460
472
}
@@ -503,6 +515,8 @@ public void execute() {
503
515
504
516
PsiDocumentManager manager = PsiDocumentManager .getInstance (psiFile .getProject ());
505
517
Document document = manager .getDocument (psiFile );
518
+ if (document == null ) return ;
519
+
506
520
manager .doPostponedOperationsAndUnblockDocument (document );
507
521
508
522
int offset = 0 ;
0 commit comments