1
1
import { window , StatusBarAlignment , StatusBarItem } from "vscode" ;
2
2
import { activeReplWindow } from '../repl-window' ;
3
+
4
+ import { onNReplEvent } from "../nrepl" ;
5
+ import { NReplEvaluationStartedEvent , NReplEvaluationFinishedEvent } from "../nrepl/events" ;
6
+
3
7
import configReader from "../configReader" ;
4
8
import * as state from '../state' ;
5
9
import * as util from '../utilities' ;
6
10
11
+ export interface EvaluationError {
12
+ fileName : string ;
13
+ filePath : string ;
14
+ message : string ;
15
+ }
16
+
7
17
export class FileTypeStatusBarItem {
8
18
private statusBarItem : StatusBarItem ;
19
+
20
+ private activeEvals = new Array < string > ( ) ;
21
+
22
+ private errors = new Array < EvaluationError > ( ) ;
23
+
24
+ private get isEvaluating ( ) {
25
+ return this . activeEvals . length > 0 ;
26
+ }
27
+
28
+ private get hasErrors ( ) {
29
+ return this . errors . length > 0 ;
30
+ }
31
+
9
32
constructor ( alignment : StatusBarAlignment ) {
10
33
this . statusBarItem = window . createStatusBarItem ( alignment ) ;
34
+ // TODO: Event handling and resulting state should be moved to global state
35
+ onNReplEvent ( this . handleNreplEvent ) ;
11
36
}
12
37
13
38
update ( ) {
@@ -23,19 +48,22 @@ export class FileTypeStatusBarItem {
23
48
24
49
if ( connected ) {
25
50
if ( fileType == 'cljc' && sessionType !== null && ! activeReplWindow ( ) ) {
26
- text = "cljc/" + sessionType ;
51
+ text = this . statusTextDecorator ( "cljc/" + sessionType ) ;
27
52
if ( util . getSession ( 'clj' ) !== null && util . getSession ( 'cljs' ) !== null ) {
28
53
command = "calva.toggleCLJCSession" ;
29
54
tooltip = `Click to use ${ ( sessionType === 'clj' ? 'cljs' : 'clj' ) } REPL for cljc` ;
30
55
}
31
56
} else if ( sessionType === 'cljs' ) {
32
- text = "cljs" ;
57
+ text = this . statusTextDecorator ( "cljs" ) ;
33
58
tooltip = "Connected to ClojureScript REPL" ;
34
59
} else if ( sessionType === 'clj' ) {
35
- text = "clj" ;
60
+ text = this . statusTextDecorator ( "clj" ) ;
36
61
tooltip = "Connected to Clojure REPL" ;
37
62
}
38
- color = configReader . colors . typeStatus ;
63
+ color = this . connectedStatusColor ( ) ;
64
+ if ( this . hasErrors ) {
65
+ tooltip = this . errorTooltip ( ) ;
66
+ }
39
67
}
40
68
41
69
this . statusBarItem . command = command ;
@@ -45,6 +73,70 @@ export class FileTypeStatusBarItem {
45
73
this . statusBarItem . show ( ) ;
46
74
}
47
75
76
+ private statusTextDecorator ( text ) : string {
77
+ if ( this . hasErrors ) {
78
+ const c = this . errors . length ;
79
+ text = `${ text } $(alert) ${ c > 1 ? c : "" } `
80
+ }
81
+ if ( this . isEvaluating ) {
82
+ text = text + " $(gear~spin)" ;
83
+ }
84
+ return text ;
85
+ }
86
+
87
+ private connectedStatusColor ( ) : string {
88
+ const c = configReader . colors ;
89
+ if ( this . hasErrors ) {
90
+ return c . error ;
91
+ } else if ( this . isEvaluating ) {
92
+ return c . launching ;
93
+ }
94
+ return c . typeStatus ;
95
+ }
96
+
97
+ private errorTooltip ( ) : string {
98
+ if ( this . errors . length > 1 ) {
99
+ return "There are errors in multiple files" ;
100
+ }
101
+ const err = this . errors [ 0 ] ;
102
+ return `Error: ${ err . fileName } : ${ err . message } ` ;
103
+ }
104
+
105
+ private handleNreplEvent = ( e : NReplEvaluationStartedEvent | NReplEvaluationFinishedEvent ) => {
106
+ switch ( e . type ) {
107
+ case "started" :
108
+ this . removeError ( e . filePath ) ;
109
+ this . activeEvals . push ( e . filePath ) ;
110
+ break ;
111
+ case "finished" :
112
+ this . removeActive ( e . filePath ) ;
113
+ const fe = < NReplEvaluationFinishedEvent > e ;
114
+ if ( fe . error ) {
115
+ this . errors . push ( {
116
+ fileName : fe . fileName ,
117
+ filePath : fe . filePath ,
118
+ message : fe . error
119
+ } ) ;
120
+ }
121
+ break ;
122
+ }
123
+ this . update ( ) ;
124
+ }
125
+
126
+ private removeActive ( filePath : string ) {
127
+ const idx = this . activeEvals . indexOf ( filePath ) ;
128
+ if ( idx !== - 1 ) {
129
+ this . activeEvals . splice ( idx , 1 ) ;
130
+ }
131
+ }
132
+
133
+ private removeError ( filePath : string ) {
134
+ const idx = this . errors . findIndex ( e => e . filePath === filePath ) ;
135
+ if ( idx !== - 1 ) {
136
+ this . errors . splice ( idx , 1 ) ;
137
+ }
138
+ }
139
+
48
140
dispose ( ) {
49
141
this . statusBarItem . dispose ( ) ;
50
142
}
0 commit comments