1
1
import * as React from '@theia/core/shared/react' ;
2
2
import { Event } from '@theia/core/lib/common/event' ;
3
3
import { DisposableCollection } from '@theia/core/lib/common/disposable' ;
4
- // import { areEqual } from 'react-window ';
4
+ import { spawnCommand } from '../../../node/exec-util ' ;
5
5
6
6
export type Line = { message : string ; lineLen : number } ;
7
+ export type Element = {
8
+ address : string ;
9
+ function : string ;
10
+ path : {
11
+ value : string ;
12
+ isLink : boolean ;
13
+ }
14
+ lineNumber : string
15
+ } ;
7
16
8
17
export class DecodeOutput extends React . Component <
9
18
DecodeOutput . Props ,
@@ -13,41 +22,83 @@ export class DecodeOutput extends React.Component<
13
22
* Do not touch it. It is used to be able to "follow" the serial monitor log.
14
23
*/
15
24
protected toDisposeBeforeUnmount = new DisposableCollection ( ) ;
16
- private listRef : React . RefObject < any > ;
17
25
18
26
constructor ( props : Readonly < DecodeOutput . Props > ) {
19
27
super ( props ) ;
20
- this . listRef = React . createRef ( ) ;
21
28
this . state = {
22
- lines : [ ] ,
23
- charCount : 0 ,
24
- text : '' ,
29
+ elements : [ ] ,
25
30
} ;
26
31
}
27
32
28
- decodeText = ( value : string ) => {
29
- this . setState ( { text : value } ) ;
33
+ isClientPath = async ( path :string ) : Promise < boolean > => {
34
+ return await spawnCommand ( "cd" , [
35
+ path
36
+ ] , ( err ) => err )
37
+ . then ( ( data ) => true )
38
+ . catch ( err => false )
39
+ }
40
+
41
+ openFinder = async ( path :string ) => {
42
+ await spawnCommand ( "open" , [
43
+ path
44
+ ] ) ;
45
+ }
46
+
47
+ retrievePath = ( dirPath :string ) => {
48
+ return dirPath . substring ( 0 , dirPath . lastIndexOf ( "/" ) + 1 ) ;
49
+ }
50
+
51
+ decodeText = async ( value : string ) => {
52
+ const lines = value . split ( "\n" ) ;
53
+
54
+ // Remove the extra newline at the end
55
+ lines . pop ( ) ;
56
+ const elements : Array < Element > = [ ] ;
57
+ for ( let i = 0 ; i < lines . length ; i ++ ) {
58
+ let line = lines [ i ] . split ( / (? ! \( .* ) \s (? ! [ ^ ( ] * ?\) ) / g) ;
59
+ if ( line [ 0 ] === "" ) {
60
+ line . shift ( ) ;
61
+ }
62
+ let pathSplit = line [ 3 ] . split ( ":" ) ;
63
+ let obj : Element = {
64
+ address : line [ 0 ] ,
65
+ function : line [ 1 ] ,
66
+ path : {
67
+ value : pathSplit [ 0 ] ,
68
+ isLink : false ,
69
+ } ,
70
+ lineNumber : pathSplit [ 1 ]
71
+ } ;
72
+ if ( await this . isClientPath ( this . retrievePath ( pathSplit [ 0 ] ) ) ) {
73
+ obj = {
74
+ address : line [ 0 ] ,
75
+ function : line [ 1 ] ,
76
+ path : {
77
+ value : pathSplit [ 0 ] ,
78
+ isLink : true ,
79
+ } ,
80
+ lineNumber : pathSplit [ 1 ]
81
+ } ;
82
+ }
83
+ elements . push ( obj ) ;
84
+ }
85
+ this . setState ( { elements } ) ;
30
86
} ;
31
87
32
88
override render ( ) : React . ReactNode {
33
89
return (
34
- // <List
35
- // className="serial-monitor-messages"
36
- // height={this.props.height}
37
- // itemData={
38
- // {
39
- // lines: this.state.lines,
40
- // } as any
41
- // }
42
- // itemCount={this.state.lines.length}
43
- // itemSize={18}
44
- // width={'100%'}
45
- // style={{ whiteSpace: 'nowrap' }}
46
- // ref={this.listRef}
47
- // >
48
- // {Row}
49
- // </List>
50
- < div style = { { whiteSpace : 'pre-wrap' } } > { this . state . text } </ div >
90
+ < div style = { { whiteSpace : 'pre-wrap' } } >
91
+ { this . state . elements . map ( ( element ) => (
92
+ < div style = { { display : "inline-block" } } >
93
+ < span style = { { color : "green" } } > { element . address } </ span >
94
+ < span style = { { color : "blue" , fontWeight : "bold" } } > { element . function } </ span >
95
+ at
96
+ { element . path . isLink ? < a > < span onClick = { async ( ) => await this . openFinder ( this . retrievePath ( element . path . value ) ) } > { element . path . value } </ span > </ a > : < span > { element . path . value } </ span > }
97
+ line
98
+ < span style = { { fontWeight : "bold" } } > { element . lineNumber } </ span >
99
+ </ div >
100
+ ) ) }
101
+ </ div >
51
102
) ;
52
103
}
53
104
@@ -56,10 +107,9 @@ export class DecodeOutput extends React.Component<
56
107
}
57
108
58
109
override componentDidMount ( ) : void {
59
- this . scrollToBottom ( ) ;
60
110
this . toDisposeBeforeUnmount . pushAll ( [
61
111
this . props . clearConsoleEvent ( ( ) =>
62
- this . setState ( { lines : [ ] , charCount : 0 } )
112
+ this . setState ( { elements : [ ] } )
63
113
) ,
64
114
] ) ;
65
115
}
@@ -68,46 +118,16 @@ export class DecodeOutput extends React.Component<
68
118
// TODO: "Your preferred browser's local storage is almost full." Discard `content` before saving layout?
69
119
this . toDisposeBeforeUnmount . dispose ( ) ;
70
120
}
71
-
72
- scrollToBottom = ( ( ) : void => {
73
- if ( this . listRef . current ) {
74
- this . listRef . current . scrollToItem ( this . state . lines . length , 'end' ) ;
75
- }
76
- } ) . bind ( this ) ;
77
121
}
78
122
79
- // const _Row = ({
80
- // index,
81
- // style,
82
- // data,
83
- // }: {
84
- // index: number;
85
- // style: any;
86
- // data: { lines: Line[]; timestamp: boolean };
87
- // }) => {
88
- // return (
89
- // (data.lines[index].lineLen && (
90
- // <div style={style}>
91
- // <pre>
92
- // {data.lines[index].message}
93
- // </pre>
94
- // </div>
95
- // )) ||
96
- // null
97
- // );
98
- // };
99
- // const Row = React.memo(_Row, areEqual);
100
-
101
123
export namespace DecodeOutput {
102
124
export interface Props {
103
125
readonly clearConsoleEvent : Event < void > ;
104
126
readonly height : number ;
105
127
}
106
128
107
129
export interface State {
108
- lines : Line [ ] ;
109
- charCount : number ;
110
- text : string ;
130
+ elements : Element [ ] ;
111
131
}
112
132
113
133
export interface SelectOption < T > {
0 commit comments