import { OutputChannel , Uri , workspace } from 'coc.nvim' ; import fs from 'fs' ; import path from 'path' ; import { promisify } from 'util' ; import Git from './git' ; export interface GitDocument { uri : string ; buftype : string ; schema : string ; } async function getRealPath ( fullpath ) { let resolved ; try { resolved = await promisify ( fs . realpath ) ( fullpath , 'utf8' ) ; } catch ( e ) { if ( e . message . includes ( 'ENOENT' ) ) { try { resolved = await workspace . nvim . call ( 'expand' , [ fullpath ] ) as string ; } catch ( e ) { } } } return resolved || fullpath ; } export default class Resolver { private resolvedRoots : Map < string , string > = new Map ( ) ; private relativePaths : Map < string , string > = new Map ( ) ; constructor ( private git , private channel ) { } public delete ( uri ) { this . resolvedRoots . delete ( uri ) ; this . relativePaths . delete ( uri ) ; } public clear ( ) { this . resolvedRoots . clear ( ) ; this . relativePaths . clear ( ) ; } public getRelativePath ( uri ) { return this . relativePaths . get ( uri ) ; } public async resolveGitRoot ( doc ? ) { if ( ! doc ) return null ; let root ; const { uri } = doc ; root = this . resolvedRoots . get ( uri ) ; if ( root ) return root ; if ( doc . buftype == 'acwrite' ) { root = await this . resolveRootFromCwd ( ) ; this . resolvedRoots . set ( uri , root ) ; return root ; } if ( doc . buftype != '' || doc . schema != 'file' ) { return null ; } let fullpath = await getRealPath ( Uri . parse ( uri ) . fsPath ) ; if ( process . platform == 'win32' ) { fullpath = path . win32 . normalize ( fullpath ) ; } if ( ! root ) { let parts = fullpath . split ( path . sep ) ; let idx = parts . indexOf ( '.git' ) ; if ( idx !== - 1 ) { root = parts . slice ( 0 , idx ) . join ( path . sep ) ; this . resolvedRoots . set ( uri , root ) ; } else { try { root = await this . git . getRepositoryRoot ( path . dirname ( fullpath ) ) ; if ( path . isAbsolute ( root ) ) { this . resolvedRoots . set ( uri , root ) ; } else { root = undefined ; } } catch ( e ) { } } } if ( root ) { this . relativePaths . set ( uri , path . relative ( root , fullpath ) ) ; } this . channel . appendLine ( `resolved root of ${ fullpath }: ${ root }` ) ; return root ; } public async resolveRootFromCwd ( ) { let parts = workspace . cwd . split ( path . sep ) ; let idx = parts . indexOf ( '.git' ) ; if ( idx !== - 1 ) return parts . slice ( 0 , idx ) . join ( path . sep ) ; try { return await this . git . getRepositoryRoot ( workspace . cwd ) ; } catch ( e ) { } return null ; } public dispose ( ) { this . resolvedRoots . clear ( ) ; this . relativePaths . clear ( ) ; } }