UNPKG

vscode-projects-plus

Version:

An extension for managing projects. Feature rich, customizable, automatically finds your projects

222 lines (126 loc) 4.96 kB
/* IMPORT */ import * as _ from 'lodash'; import * as JSON5 from 'json5'; import * as os from 'os'; import * as path from 'path'; import * as vscode from 'vscode'; import Utils from './utils'; /* CONFIG */ const Config = { getDefaults () { return { configPath: path.join ( os.homedir (), 'vscode_projects.json' ) }; }, getExtension ( extension = 'projects' ) { const config = Config.untildify ( vscode.workspace.getConfiguration ().get ( extension ) ) as any; if ( !config.configPath ) delete config.configPath; return config; }, async getFile ( filePath ) { const content = await Utils.file.read ( filePath ); if ( !content || !content.trim () ) return; const config: any = _.attempt ( JSON5.parse, content ); if ( _.isError ( config ) ) { const option = await vscode.window.showErrorMessage ( '[Projects+] Your configuration file contains improperly formatted JSON', { title: 'Overwrite' }, { title: 'Edit' } ); if ( option && option.title === 'Overwrite' ) { await Utils.file.write ( filePath, '{}' ); return {}; } else { if ( option && option.title === 'Edit' ) { Utils.file.open ( filePath ); } throw new Error ( 'Can\'t read improperly formatted configuration file' ); } } return config; }, async get () { const defaults = Config.getDefaults (), extension: any = Config.getExtension (), configPath: string = extension.configPath || defaults.configPath, config = configPath && await Config.getFile ( configPath ); return _.merge ( {}, defaults, extension, config ); }, async write ( filePath, config ) { const newConfig = _.omit ( config, ['configPath'] ); await Utils.file.write ( filePath, JSON.stringify ( newConfig, undefined, 2 ) ); const {default: Statusbar} = require ( './statusbar' ); // In order to avoid cyclic dependency Statusbar.update (); Utils.ui.refresh (); }, untildify ( config ) { const keys = ['configPath', 'refreshIgnoreFolders', 'refreshRoots']; keys.forEach ( key => { if ( config[key] ) { if ( _.isArray ( config[key] ) ) { config[key] = config[key].map ( Utils.path.untildify ); } else { config[key] = Utils.path.untildify ( config[key] ); } } }); return config; }, merge ( config, ...otherConfigs ) { /* ROUGH MERGE */ // Based on the assumpion that all arrays are either groups or projects function roughMerge ( config, ...otherConfigs ) { return _.mergeWith ( config, ...otherConfigs, ( prev, next ) => { if ( !_.isArray ( prev ) || !_.isArray ( next ) ) return; next.forEach ( nextItem => { const prevItem = prev.find ( prevItem => prevItem.name === nextItem.name ); //FIXME: Maybe check if they have the same path if ( !prevItem ) { prev.push ( nextItem ); } else { if ( prevItem.path && nextItem.path && prevItem.path.endsWith ( '.code-workspace' ) && !nextItem.path.endsWith ( '.code-workspace' ) ) { nextItem.path = prevItem.path; } roughMerge ( prevItem, nextItem ); } }); return prev; }); } const merged = roughMerge ( config, ...otherConfigs ) as any; /* REMOVE UNGROUPED DUPLICATES */ if ( merged.groups && merged.projects ) { const pathNormalize = path => Utils.path.untildify ( path ).toLowerCase (), paths = Utils.config.getProjectsPaths ({ groups: merged.groups }).map ( pathNormalize ); merged.projects = merged.projects.filter ( project => !_.includes ( paths, pathNormalize ( project.path ) ) ); } /* RETURN */ return merged; }, onChangeListening: false, onChangeCallbacks: [], async onChangeListener () { let config = await Config.get (), watcher: vscode.FileSystemWatcher; async function handleChange () { const newConfig = await Config.get (); if ( _.isEqual ( config, newConfig ) ) return; if ( config.configPath !== newConfig.configPath ) watchConfig (); config = newConfig; Config.onChangeCallbacks.forEach ( callback => callback ( config ) ); } function watchConfig () { if ( watcher ) watcher.dispose (); watcher = vscode.workspace.createFileSystemWatcher ( config.configPath ); watcher.onDidChange ( handleChange ); } function watchWorkspaceConfiguration () { vscode.workspace.onDidChangeConfiguration ( handleChange ); } watchConfig (); watchWorkspaceConfiguration (); }, async onChange ( callback ) { if ( !Config.onChangeListening ) { Config.onChangeListener (); Config.onChangeListening = true; } Config.onChangeCallbacks.push ( callback ); } }; /* EXPORT */ export default Config;