11'use strict' ;
22
3- import { workspace , WorkspaceConfiguration } from 'vscode' ;
3+ import { window , workspace , WorkspaceConfiguration } from 'vscode' ;
44import * as path from 'path' ;
55import * as fs from 'fs' ;
66
@@ -16,42 +16,134 @@ function folderExists(path: fs.PathLike)
1616 }
1717}
1818
19- function checkFileExists ( filePath : fs . PathLike ) {
19+ function checkFileExists ( filePath : fs . PathLike , checkExec : boolean = false ) {
2020 try {
21- return ( fs . statSync ( filePath ) ) . isFile ( ) ;
21+ let isfile = fs . statSync ( filePath ) . isFile ( ) ;
22+ if ( ! isfile ) {
23+ window . showErrorMessage ( 'Cannot access file: ' + filePath ) ;
24+ }
25+ if ( checkExec && isfile ) {
26+ if ( ! isExec ( filePath ) ) {
27+ window . showErrorMessage ( 'Not an executable: ' + filePath ) ;
28+ return false ;
29+ }
30+ return true ;
31+ } else {
32+ return isfile ;
33+ }
2234 } catch ( err ) {
2335 return false ;
2436 }
2537}
2638
39+ function isExec ( p : fs . PathLike ) {
40+ try {
41+ fs . accessSync ( p , fs . constants . X_OK ) ;
42+ return true ;
43+ } catch ( e ) {
44+ return false ;
45+ }
46+ }
47+
48+ function parseDate ( date : string ) {
49+ const months = [
50+ 'jan' , 'feb' , 'mar' , 'apr' , 'may' , 'jun' ,
51+ 'jul' , 'aug' , 'sep' , 'oct' , 'nov' , 'dec'
52+ ] ;
53+
54+ const day = Number ( date . slice ( 0 , 2 ) ) ;
55+ const month = months . indexOf ( date . slice ( 2 , 5 ) . toLowerCase ( ) ) ;
56+ const year = Number ( date . slice ( 5 , 7 ) ) ;
57+ if ( Number . isNaN ( year ) || Number . isNaN ( day ) || month === - 1 ) {
58+ return undefined ;
59+ }
60+ return new Date ( year , month , day ) ;
61+ }
62+
63+ function searchRedTool ( name : string , searchPath : string ) {
64+ try {
65+ const expectExt = process . platform === 'win32' ? '.exe' : '' ;
66+ let files = fs . readdirSync ( searchPath ) ;
67+ let tool = '' ;
68+ let toolDate = new Date ( 1800 , 0 ) ;
69+ let startsWith = name + '-' ;
70+ for ( let f of files ) {
71+ let ext = path . extname ( f ) ;
72+ let parts = path . basename ( f , ext ) . slice ( startsWith . length ) . split ( "-" ) ;
73+ if ( f . startsWith ( startsWith ) && parts . length === 2 && parts [ 0 ] . length === 7 && ext === expectExt ) {
74+ let fpath = path . join ( searchPath , f ) ;
75+ let date = parseDate ( parts [ 0 ] ) ;
76+ let d = fs . statSync ( fpath ) . mtime ;
77+ if ( date !== undefined ) {
78+ date . setHours ( d . getHours ( ) , d . getMinutes ( ) , d . getSeconds ( ) ) ;
79+ if ( tool === '' ) {
80+ toolDate = date ;
81+ tool = fpath ;
82+ } else {
83+ if ( date > toolDate ) {
84+ toolDate = date ;
85+ tool = fpath ;
86+ }
87+ }
88+ }
89+ }
90+ }
91+ if ( tool === '' ) {
92+ tool = path . join ( searchPath , name + expectExt ) ;
93+ if ( ! fs . statSync ( tool ) . isFile ( ) ) { return '' ; } ;
94+ }
95+ return tool ;
96+ }
97+ catch ( err ) {
98+ return '' ;
99+ }
100+ }
101+
27102/**
28103 * @param {string } exe executable name (without extension if on Windows)
29104 * @return {string|null } executable path if found
30105 * */
31- function findExecutable ( exe : string ) {
32- const envPath = process . env . PATH || "" ;
106+ function findExecutable ( exe : string , searchPath : string = '' ) {
107+ let useOSPath = false ;
108+ if ( searchPath === '' ) {
109+ useOSPath = true ;
110+ searchPath = process . env . PATH || "" ;
111+ }
33112 let ext : string ;
34113 if ( process . platform === 'win32' ) {
35114 ext = ".exe" ;
36115 } else {
37116 ext = "" ;
38117 }
39- const pathDirs = envPath
118+ const pathDirs = searchPath
40119 . replace ( / [ " ] + / g, "" )
41120 . split ( path . delimiter )
42121 . filter ( Boolean ) ;
43- const candidates = pathDirs . map ( ( d ) => path . join ( d , exe + ext ) ) ;
44- for ( let i in candidates ) {
45- if ( checkFileExists ( candidates [ i ] ) ) { return candidates [ i ] ; } ;
122+
123+ if ( useOSPath ) {
124+ const candidates = pathDirs . map ( ( d ) => path . join ( d , exe + ext ) ) ;
125+ for ( let i in candidates ) {
126+ if ( checkFileExists ( candidates [ i ] , true ) ) { return candidates [ i ] ; } ;
127+ }
128+ } else {
129+ for ( let dir of pathDirs ) {
130+ let tool = searchRedTool ( exe , dir ) ;
131+ if ( tool !== '' ) {
132+ return checkFileExists ( tool , true ) ? tool : '' ;
133+ }
134+ }
46135 }
47136 return '' ;
48137}
49138
50- function getRedConsole ( gui : boolean ) {
139+ function getRedTool ( name : string , toolDir : string = '' , gui : boolean = false ) {
140+ if ( toolDir !== '' ) {
141+ let exe = findExecutable ( name , toolDir ) ;
142+ if ( exe !== '' ) { return exe ; }
143+ }
144+
51145 if ( process . platform === 'win32' ) {
52146 // There is a `red` program on Linux already
53- let name = 'red' ;
54- if ( gui ) { name = 'red-view' ; }
55147 let exe = findExecutable ( name ) ;
56148 if ( exe !== '' ) { return exe ; }
57149 }
@@ -88,8 +180,10 @@ function getRedConsole(gui: boolean) {
88180 }
89181 }
90182 }
183+ if ( _console === '' ) { return '' ; }
184+
91185 let exe = path . join ( preBuiltPath , _console ) ;
92- return checkFileExists ( exe ) ? exe : '' ;
186+ return checkFileExists ( exe , true ) ? exe : '' ;
93187 }
94188 catch ( err ) {
95189 return '' ;
@@ -109,17 +203,32 @@ export class RedConfiguration {
109203 return this . configuration . get < boolean > ( 'red.rls-debug' , false ) ;
110204 }
111205
206+ public get redDir ( ) : string {
207+ return this . configuration . get < string > ( 'red.redDir' , '' ) ;
208+ }
209+
112210 public get redCore ( ) : string {
113- return this . configuration . get < string > ( 'red.redPath' , '' ) ;
211+ let exe = this . configuration . get < string > ( 'red.redPath' , '' ) ;
212+ if ( exe !== '' && ! checkFileExists ( exe , true ) ) {
213+ return '' ;
214+ }
215+ return exe ;
114216 }
115217
116218 public get redView ( ) : string {
117- return this . configuration . get < string > ( 'red.redViewPath' , '' ) ;
219+ let exe = this . configuration . get < string > ( 'red.redViewPath' , '' ) ;
220+ if ( exe !== '' && ! checkFileExists ( exe , true ) ) {
221+ return '' ;
222+ }
223+ return exe ;
118224 }
119225
120226 public get redToolChain ( ) : string {
121227 let path = this . configuration . get < string > ( 'red.redToolChainPath' , '' ) ;
122- return path === '' ? findExecutable ( "red-toolchain" ) : path ;
228+ if ( path !== '' && ! checkFileExists ( path , true ) ) {
229+ return '' ;
230+ }
231+ return path === '' ? findExecutable ( "red-toolchain" , this . redDir ) : path ;
123232 }
124233
125234 public get redExcludedPath ( ) : string {
@@ -128,12 +237,12 @@ export class RedConfiguration {
128237
129238 public get redConsole ( ) : string {
130239 let path = this . redCore ;
131- return path === '' ? getRedConsole ( false ) : path ;
240+ return path === '' ? getRedTool ( "red" , this . redDir ) : path ;
132241 }
133242
134243 public get redGuiConsole ( ) : string {
135244 let path = this . redView ;
136- return path === '' ? getRedConsole ( true ) : path ;
245+ return path === '' ? getRedTool ( "red-view" , this . redDir , true ) : path ;
137246 }
138247
139248 public get redWorkSpace ( ) : string {
0 commit comments