@@ -10,6 +10,10 @@ const copyPaste = require("copy-paste");
1010
1111const extensionName = 'Github-File-Url' ;
1212
13+ const TYPE = {
14+ git_config : '.git/config' ,
15+ git_modules : '.gitmodules' ,
16+ } ;
1317
1418// This method is called when your extension is activated
1519// Your extension is activated the very first time the command is executed
@@ -43,7 +47,7 @@ function executeCommandAllTextEditors(commandName) {
4347 return ;
4448 }
4549
46- textEditors . forEach ( p => uniquePaths [ p . fileName ] = true ) ;
50+ textEditors . forEach ( p => uniquePaths [ p . fileName ] = true ) ;
4751
4852 const allPaths = [ ] ;
4953 const allErrors = [ ] ;
@@ -55,7 +59,7 @@ function executeCommandAllTextEditors(commandName) {
5559 case 'success' :
5660 {
5761 const url = result . url ;
58- const relativeFilePath = result . relativeFilePath ;
62+ const relativeFilePath = result . relativePathFromGitRoot ;
5963 const urlMarkdownLink = `[${ relativeFilePath } ](${ url } )` ;
6064 allPaths . push ( urlMarkdownLink ) ;
6165 }
@@ -134,7 +138,7 @@ function executeCommand1(commandName, fileUri, pullLines) {
134138 case 'success' :
135139 {
136140 const url = result . url ;
137- const relativeFilePath = result . relativeFilePath ;
141+ const relativeFilePath = result . relativePathFromGitRoot ;
138142 const urlMarkdownLink = `[${ relativeFilePath } ](${ url } )` ;
139143 copyPaste . copy ( urlMarkdownLink ) ;
140144 }
@@ -175,27 +179,44 @@ Workspace Root: ${workspaceRootPath}`;
175179
176180function generateGithubUrl ( commandName , workspaceRootPath , filePath , lineSelection ) {
177181 try {
178- const parseResult = findAndParseConfig ( workspaceRootPath ) ;
182+ workspaceRootPath = workspaceRootPath . replace ( / \\ / g, '/' ) ; // Flip subdir slashes on Windows
183+ filePath = filePath . replace ( / \\ / g, '/' ) ; // Flip subdir slashes on Windows
184+ const parseResult = findAndParseConfig ( filePath ) ;
179185 if ( ! parseResult ) {
180186 const errorMessage = `${ extensionName } extension failed to find a Github config at the workspace folder or any of it's parent folders.
181187Is this a Github repository?
182188
183- Workspace Root: ${ workspaceRootPath } ` ;
189+ Workspace Root: ${ workspaceRootPath }
190+ Filepath: ${ filePath } ` ;
184191 return {
185192 type : 'error' ,
186193 errorMessage,
187194 } ;
188195 }
189196 const config = parseResult . config ;
190- const cwd = parseResult . rootPath ;
191- const branch = gitBranch . sync ( cwd ) ;
197+ const rootPathForGitConfig = parseResult . rootPath ;
198+ const branch = gitBranch . sync ( rootPathForGitConfig ) ;
192199 const remoteConfig = config [ `branch "${ branch } "` ] ;
193200 const remoteName = remoteConfig && remoteConfig . remote ? remoteConfig . remote : 'origin' ;
194201 const finalConfig = config [ `remote "${ remoteName } "` ] ;
195202 if ( finalConfig ) {
196- const githubRootUrl = githubUrlFromGit ( finalConfig . url ) ;
197- let relativeFilePath = filePath . substring ( cwd . length ) . replace ( / \\ / g, '/' ) ; // Flip subdir slashes on Windows
203+ let targetUrl = finalConfig . url ;
204+ let targetPath = rootPathForGitConfig ;
205+ for ( const sub of parseResult . subModules ) {
206+ if ( filePath . search ( sub . path ) === 0 ) {
207+ targetUrl = sub . url ;
208+ targetPath = sub . path ;
209+ break ;
210+ }
211+ }
212+
213+ const githubRootUrl = githubUrlFromGit ( targetUrl ) ;
214+ let relativePathFromGitRoot = filePath . substring ( rootPathForGitConfig . length ) . replace ( / \\ / g, '/' ) ; // Flip subdir slashes on Windows
215+ let relativeFilePath = filePath . substring ( targetPath . length ) . replace ( / \\ / g, '/' ) ; // Flip subdir slashes on Windows
198216 let url = `${ githubRootUrl } /blob/${ branch } ${ relativeFilePath } ` ;
217+ if ( relativePathFromGitRoot [ 0 ] === '/' ) {
218+ relativePathFromGitRoot = relativePathFromGitRoot . slice ( 1 ) ;
219+ }
199220 if ( relativeFilePath [ 0 ] === '/' ) {
200221 relativeFilePath = relativeFilePath . slice ( 1 ) ;
201222 }
@@ -214,12 +235,14 @@ Workspace Root: ${workspaceRootPath}`;
214235 type : 'success' ,
215236 url,
216237 relativeFilePath,
238+ relativePathFromGitRoot,
217239 }
218240 } else {
219241 let errorMessage = `${ extensionName } extension failed to find a remote config for "${ remoteName } " in branch "${ branch } ".
220242Is this a Github repository?
221243
222- Workspace Root: ${ workspaceRootPath } ` ;
244+ Workspace Root: ${ workspaceRootPath }
245+ Filepath: ${ filePath } ` ;
223246 return {
224247 type : 'error' ,
225248 errorMessage,
@@ -238,26 +261,90 @@ Workspace Root: ${workspaceRootPath}`;
238261 }
239262}
240263
264+ const reSubModulePuller = / " ( [ ^ " ] * ) " / g;
265+
241266function findAndParseConfig ( rootPath ) {
242- function intParseConfig ( cwd ) {
243- let ret = parseConfig . sync ( { cwd : cwd , path : '.git/config' } ) ;
267+ function intParseGitConfig ( cwd ) {
268+ let ret = parseConfig . sync ( { cwd : cwd , path : TYPE . git_config } ) ;
269+ if ( ! ( Object . keys ( ret ) . length === 0 && ret . constructor === Object ) ) {
270+ return ret ;
271+ }
272+ }
273+ function intParseModuleConfig ( cwd ) {
274+ let ret = parseConfig . sync ( { cwd : cwd , path : TYPE . git_modules } ) ;
244275 if ( ! ( Object . keys ( ret ) . length === 0 && ret . constructor === Object ) ) {
245276 return ret ;
246277 }
247278 }
248279
249280 rootPath = rootPath . replace ( / \\ / g, '/' ) ; // Flip subdir slashes on Windows
250281 const pathParts = rootPath . split ( '/' ) ;
282+ let subModuleConfigs = [ ] ;
283+ let subModules = [ ] ;
251284 let stepsUp = 0 ;
252285 while ( pathParts . length > 0 ) {
253286 let currentPath = pathParts . join ( '/' ) ;
254- let config = intParseConfig ( currentPath ) ;
255- if ( config ) {
256- return {
287+ let gitConfig = intParseGitConfig ( currentPath ) ;
288+ function pullSubModules ( subMeta ) {
289+ const config = subMeta . config ;
290+ const ret = [ ] ;
291+ for ( const key in config ) {
292+ const match1 = reSubModulePuller . exec ( key ) ;
293+ if ( match1 && match1 . length === 2 ) {
294+ const subConfig = config [ key ] ;
295+ const subUrl = subConfig . url ;
296+ const modName = match1 [ 1 ] ;
297+ const modFullpath = path . join ( currentPath , modName ) . replace ( / \\ / g, '/' ) ;
298+ if ( ! subUrl ) {
299+ console . warn ( `subModule '${ name } ' at '${ modFullpath } ' is missing a url, it will be skipped` ) ;
300+ } else {
301+ const metaInfo = {
302+ path : modFullpath ,
303+ name : modName ,
304+ url : subUrl ,
305+ } ;
306+ subModules . push ( metaInfo ) ;
307+ ret . push ( metaInfo ) ;
308+ }
309+ }
310+ }
311+ return ret ;
312+ }
313+ if ( gitConfig ) {
314+
315+ const pathMap = [ ] ;
316+ for ( const sub of subModuleConfigs ) {
317+ const subRoot = sub . path ;
318+ // const fullModulePath = path.join(sub.)).replace(/\\/g, '/')
319+ // pathMap
320+ }
321+
322+ const rootMeta = {
323+ type : TYPE . git_config ,
257324 rootPath : currentPath ,
258- config,
259- stepsUp
325+ path : currentPath ,
326+ config : gitConfig ,
327+ stepsUp,
260328 } ;
329+ const subs = pullSubModules ( rootMeta ) ;
330+ rootMeta . subs = subs ;
331+
332+ rootMeta . subModules = subModules ;
333+
334+ return rootMeta ;
335+ } else {
336+ let moduleConfig = intParseModuleConfig ( currentPath ) ;
337+ if ( moduleConfig ) {
338+ const subMeta = {
339+ type : TYPE . git_modules ,
340+ path : currentPath ,
341+ config : moduleConfig ,
342+ stepsUp,
343+ } ;
344+ const subs = pullSubModules ( subMeta ) ;
345+ subMeta . subs = subs ;
346+ subModuleConfigs . push ( subMeta ) ;
347+ }
261348 }
262349 stepsUp ++ ;
263350 pathParts . pop ( ) ;
0 commit comments