@@ -3,9 +3,10 @@ import * as NodePath from 'path';
33import * as os from 'os' ;
44import * as xml2js from 'xml2js' ;
55import { VirtualFolder } from './EIDETypeDefine' ;
6- import { VirtualSource } from './EIDEProject' ;
6+ import { VirtualSource , AbstractProject } from './EIDEProject' ;
77import { isArray } from 'util' ;
88import { ArrayDelRepetition } from '../lib/node-utility/Utility' ;
9+ import { File } from '../lib/node-utility/File' ;
910
1011export type EclipseProjectType = 'arm' | 'sdcc' | 'riscv' | 'gcc' ;
1112
@@ -104,6 +105,10 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
104105 let cprjDom = ( await xml2js . parseStringPromise (
105106 fs . readFileSync ( cprojectPath ) . toString ( ) ) ) [ 'cproject' ] ;
106107
108+ const cprojectDir = new File ( NodePath . dirname ( cprojectPath ) ) ;
109+
110+ const SRC_FILE_FILTER = AbstractProject . getSourceFileFilterWithoutObj ( ) . concat ( AbstractProject . headerFilter ) ;
111+
107112 const PROJ_INFO : EclipseProjectInfo = {
108113 name : _prjDom . name [ 0 ] . replace ( / \s + / g, '_' ) ,
109114 type : 'gcc' ,
@@ -122,6 +127,10 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
122127 if ( ! node ) throw new Error ( `not found: '<storageModule moduleId="org.eclipse.cdt.core.settings">'` ) ;
123128 cprjDom = node ;
124129
130+ const root_virtualsrcs : string [ ] = [ ] ;
131+ const root_srcdirs : string [ ] = [ ] ;
132+ const eclipseTargetList : string [ ] = [ ] ;
133+
125134 // parse all project targets
126135 for ( const ccfg of toArray ( cprjDom [ 'cconfiguration' ] ) ) {
127136
@@ -147,6 +156,8 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
147156
148157 cTarget = cTarget [ 'configuration' ] [ 0 ] ;
149158
159+ eclipseTargetList . push ( cTarget . $ [ 'name' ] ) ;
160+
150161 const tInfo : EclipseProjectTarget = {
151162 name : cTarget . $ [ 'name' ] . replace ( / \s + / g, '_' ) ,
152163 excList : [ ] ,
@@ -252,11 +263,24 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
252263 }
253264
254265 if ( cTarget . sourceEntries ) {
266+
255267 toArray ( cTarget . sourceEntries [ 0 ] . entry ) . forEach ( e => {
256268
257269 //<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="src" />
258270 if ( < string > e . $ [ 'kind' ] == 'sourcePath' ) {
259- PROJ_INFO . sourceEntries . push ( formatFilePath ( e . $ [ 'name' ] ) ) ;
271+ const srcdir = formatFilePath ( e . $ [ 'name' ] ) ;
272+ if ( srcdir == '.' || srcdir == '' ) {
273+ const srcs = cprojectDir . GetList ( SRC_FILE_FILTER , [ / ^ [ ^ \. ] .+ / ] ) ;
274+ srcs . forEach ( src => {
275+ if ( src . IsFile ( ) ) {
276+ root_virtualsrcs . push ( src . name ) ;
277+ } else {
278+ root_srcdirs . push ( src . name ) ;
279+ }
280+ } ) ;
281+ } else {
282+ root_srcdirs . push ( srcdir ) ;
283+ }
260284 }
261285
262286 ( < string > e . $ [ 'excluding' ] || '' )
@@ -268,10 +292,24 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
268292 }
269293 }
270294
295+ // setup root sources
296+ ArrayDelRepetition ( root_virtualsrcs ) . forEach ( srcpath => {
297+ PROJ_INFO . virtualSource . files . push ( { path : srcpath } ) ;
298+ } ) ;
299+ ArrayDelRepetition ( root_srcdirs ) . forEach ( srcdir => {
300+ if ( eclipseTargetList . includes ( srcdir ) ) return ; // skip eclipse build dir
301+ PROJ_INFO . sourceEntries . push ( srcdir ) ;
302+ } ) ;
303+
271304 const getVirtualFolder = ( rePath : string ) => {
272305
273- rePath = rePath . trim ( ) . replace ( / ^ \/ / , '' ) . replace ( / ^ \. \/ ? / , '' ) ;
274- if ( rePath == '' ) return PROJ_INFO . virtualSource ;
306+ rePath = rePath . trim ( )
307+ . replace ( / ^ \/ / , '' )
308+ . replace ( / \/ + $ / , '' )
309+ . replace ( / ^ \. \/ ? / , '' ) ;
310+
311+ if ( rePath == '' || rePath == '.' )
312+ return PROJ_INFO . virtualSource ;
275313
276314 let curFolder = PROJ_INFO . virtualSource ;
277315 let pathList = rePath . split ( / \\ | \/ / ) . reverse ( ) ;
@@ -296,23 +334,76 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
296334 return curFolder ;
297335 } ;
298336
337+ const virtualRootList : string [ ] = [ ] ;
338+ const virtualRootMap : { [ vpath : string ] : string } = { } ;
339+
299340 // parse external source
300341 if ( _prjDom . linkedResources ) {
301342 toArray ( _prjDom . linkedResources [ 0 ] . link ) . forEach ( link => {
302- if ( link . type [ 0 ] != '1' ) return ; // skip folder
303- const vPath = link . name [ 0 ] . trim ( ) ;
304- if ( vPath == '' ) return ;
305- const vFolder = getVirtualFolder ( NodePath . dirname ( vPath ) ) ;
306- const locations = link . locationURI || link . location ;
307- if ( ! Array . isArray ( locations ) ) return ;
308- vFolder . files . push ( { path : formatFilePath ( locations [ 0 ] ) } ) ;
343+ if ( link . type [ 0 ] == '1' ) { // virtual file
344+ const vPath = link . name [ 0 ] . trim ( ) ;
345+ if ( vPath == '' ) return ;
346+ const vFolder = getVirtualFolder ( NodePath . dirname ( vPath ) ) ;
347+ const locations = link . locationURI || link . location ;
348+ if ( ! Array . isArray ( locations ) ) return ;
349+ vFolder . files . push ( { path : formatFilePath ( locations [ 0 ] ) } ) ;
350+ } else if ( link . type [ 0 ] == '2' ) { // virtual folder
351+ const vpath = link . name [ 0 ] . trim ( ) ;
352+ const locations : string = link . locationURI || link . location ;
353+ if ( ! Array . isArray ( locations ) ) return ;
354+ const location : string = locations [ 0 ] ;
355+ if ( typeof location != 'string' ) return ;
356+ virtualRootList . push ( vpath ) ;
357+ const rootdirpath_ = formatFilePath ( location ) ;
358+ let rootdirfullpath = rootdirpath_ ;
359+ if ( ! File . isAbsolute ( rootdirpath_ ) ) rootdirfullpath = `${ cprojectDir . path } /${ rootdirpath_ } ` ;
360+ let vFolder = getVirtualFolder ( vpath ) ; // add this folder
361+ if ( File . IsDir ( rootdirfullpath ) ) {
362+ virtualRootMap [ vpath ] = File . ToUnixPath ( rootdirpath_ ) ;
363+ const files = new File ( rootdirfullpath ) . GetAll ( SRC_FILE_FILTER , File . EXCLUDE_ALL_FILTER ) ;
364+ const srcRootDir = new File ( rootdirfullpath ) ;
365+ files . forEach ( f => {
366+ let subvpath = vpath ;
367+ const dirname = srcRootDir . ToRelativePath ( f . dir ) ;
368+ if ( dirname && dirname != '.' ) subvpath += '/' + dirname ;
369+ vFolder = getVirtualFolder ( subvpath ) ;
370+ vFolder . files . push ( { path : cprojectDir . ToRelativePath ( f . path ) || f . path } ) ;
371+ } ) ;
372+ }
373+ }
309374 } ) ;
310375 }
311376
377+ const completeVirtualPaths = ( pathlist : string [ ] ) : string [ ] => {
378+ return pathlist . map ( p => {
379+ if ( virtualRootList . includes ( p ) || virtualRootList . some ( e => p . startsWith ( e + '/' ) ) ) {
380+ return `${ VirtualSource . rootName } /${ p } ` ;
381+ } else {
382+ return p ;
383+ }
384+ } ) ;
385+ } ;
386+
387+ const resolveVirtualPaths = ( pathlist : string [ ] ) : string [ ] => {
388+ return pathlist . map ( p => {
389+ for ( const rootpath of virtualRootList ) {
390+ if ( ( rootpath == p || p . startsWith ( rootpath + '/' ) ) && virtualRootMap [ rootpath ] ) {
391+ return p . replace ( rootpath , virtualRootMap [ rootpath ] ) ;
392+ }
393+ }
394+ return p ;
395+ } ) ;
396+ } ;
397+
312398 // del repeat args for every targets
313399 for ( const target of PROJ_INFO . targets ) {
314400
315- target . excList = ArrayDelRepetition ( target . excList ) ;
401+ // add prefix for virtual exclude paths
402+ target . excList = completeVirtualPaths ( ArrayDelRepetition ( target . excList ) ) ;
403+
404+ // resolve virtual include paths
405+ target . globalArgs . cIncDirs = resolveVirtualPaths ( target . globalArgs . cIncDirs ) ;
406+ target . globalArgs . sIncDirs = resolveVirtualPaths ( target . globalArgs . sIncDirs ) ;
316407
317408 for ( const key in target . globalArgs ) {
318409 const obj : any = target . globalArgs ;
@@ -336,9 +427,6 @@ export async function parseEclipseProject(cprojectPath: string): Promise<Eclipse
336427
337428function parseToolOption ( optionObj : any ) : { type : string , val : string [ ] } | undefined {
338429
339- if ( optionObj . $ [ 'valueType' ] == undefined )
340- return ;
341-
342430 if ( optionObj . $ [ 'id' ] ) {
343431 // skip output args
344432 if ( [ '.converthex' , '.convertbin' , '.convert' ]
@@ -351,13 +439,13 @@ function parseToolOption(optionObj: any): { type: string, val: string[] } | unde
351439
352440 const VALUE_NAME : string = optionObj . $ [ 'name' ] || '' ;
353441 const VALUE_VAL : string = optionObj . $ [ 'value' ] || '' ;
354- const VALUE_TYPE : string = optionObj . $ [ 'valueType' ] ;
442+ const VALUE_TYPE : string | undefined = optionObj . $ [ 'valueType' ] ;
355443
356- let makeResult = ( value : string | string [ ] ) : { type : string , val : string [ ] } | undefined => {
444+ let makeResult = ( value : string | string [ ] , typ ?: string ) : { type : string , val : string [ ] } | undefined => {
357445 if ( value == '' ) return undefined ;
358446 if ( isArray ( value ) && value . length == 0 ) return undefined ;
359447 return {
360- type : VALUE_TYPE ,
448+ type : typ || VALUE_TYPE || '' ,
361449 val : isArray ( value ) ? value : [ value ]
362450 } ;
363451 } ;
@@ -371,6 +459,43 @@ function parseToolOption(optionObj: any): { type: string, val: string[] } | unde
371459 return fmt + arg ;
372460 }
373461
462+ //
463+ // match by name
464+ //
465+
466+ // <Language Standard> = option.std.gnu99
467+ if ( / L a n g u a g e S t a n d a r d / i. test ( VALUE_NAME ) ) {
468+ const m = / s t d \. ( \w + ) / . exec ( VALUE_VAL ) ;
469+ if ( m && m . length > 1 ) {
470+ const langStd = m [ 1 ] ;
471+ return makeResult ( `-std=${ langStd } ` , 'string' ) ;
472+ }
473+ }
474+
475+ if ( VALUE_NAME . includes ( '(-D)' ) ) {
476+ const li : string [ ] = [ ] ;
477+ toArray ( optionObj . listOptionValue ) . forEach ( item => li . push ( item . $ [ 'value' ] ) ) ;
478+ return makeResult ( li , 'definedSymbols' ) ;
479+ }
480+
481+ if ( VALUE_NAME . includes ( '(-I)' ) ) {
482+ const li : string [ ] = [ ] ;
483+ toArray ( optionObj . listOptionValue ) . forEach ( item => {
484+ let p = formatFilePath ( item . $ [ 'value' ] ) ;
485+ if ( p == '..' ) p = '.' ;
486+ if ( p . startsWith ( '../' ) ) p = p . substr ( 3 ) ; // for eclipse, include path is base 'Debug' folder
487+ li . push ( p ) ;
488+ } ) ;
489+ return makeResult ( li , 'includePath' ) ;
490+ }
491+
492+ //
493+ // match by type
494+ //
495+
496+ if ( VALUE_TYPE == undefined )
497+ return ;
498+
374499 if ( VALUE_TYPE == 'boolean' ) {
375500 if ( VALUE_VAL == 'true' ) {
376501 const mRes = / \( ( \- .+ ) \) / . exec ( VALUE_NAME ) ;
0 commit comments