diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -150,6 +150,8 @@ 'PhutilDocblockParserTestCase' => 'parser/__tests__/PhutilDocblockParserTestCase.php', 'PhutilEditDistanceMatrix' => 'utils/PhutilEditDistanceMatrix.php', 'PhutilEditDistanceMatrixTestCase' => 'utils/__tests__/PhutilEditDistanceMatrixTestCase.php', + 'PhutilEditorConfig' => 'parser/PhutilEditorConfig.php', + 'PhutilEditorConfigTestCase' => 'parser/__tests__/PhutilEditorConfigTestCase.php', 'PhutilEmailAddress' => 'parser/PhutilEmailAddress.php', 'PhutilEmailAddressTestCase' => 'parser/__tests__/PhutilEmailAddressTestCase.php', 'PhutilEmptyAuthAdapter' => 'auth/PhutilEmptyAuthAdapter.php', @@ -587,6 +589,7 @@ 'PhutilDisqusAuthAdapter' => 'PhutilOAuthAuthAdapter', 'PhutilDocblockParserTestCase' => 'PhutilTestCase', 'PhutilEditDistanceMatrixTestCase' => 'PhutilTestCase', + 'PhutilEditorConfigTestCase' => 'PhutilTestCase', 'PhutilEmailAddressTestCase' => 'PhutilTestCase', 'PhutilEmptyAuthAdapter' => 'PhutilAuthAdapter', 'PhutilErrorHandlerTestCase' => 'PhutilTestCase', diff --git a/src/parser/PhutilEditorConfig.php b/src/parser/PhutilEditorConfig.php new file mode 100644 --- /dev/null +++ b/src/parser/PhutilEditorConfig.php @@ -0,0 +1,98 @@ +root = $root; + } + + public function getConfig($path, $key) { + $paths = $this->getEditorConfigPaths($path); + $editorconfigs = $this->getEditorConfigs($paths); + + foreach ($editorconfigs as $editorconfig) { + list($path_prefix, $config) = $editorconfig; + + foreach ($config as $glob => $options) { + if (!$glob) { + continue; + } + + switch (strpos($glob, '/')) { + case false: + $glob = '**/'.$glob; + break; + + case 0: + $glob = substr($glob, 1); + break; + } + + $glob = $path_prefix.'/'.$glob; + $regex = phutil_glob_to_regex($glob); + + if (!preg_match($regex, $path)) { + continue; + } + + $value = $options[$key]; + $decoded_value = json_decode($value, true); + + if ($decoded_value !== null) { + return $decoded_value; + } else { + return $options[$key]; + } + } + } + } + + private function getEditorConfigPaths($path) { + $paths = array(); + + do { + $path = dirname($path); + $paths[] = $path.'/.editorconfig'; + } while ($path != $this->root); + + return $paths; + } + + private function getEditorConfigs(array $paths) { + $configs = array(); + + foreach ($paths as $path) { + if (!Filesystem::pathExists($path)) { + continue; + } + + $config = Filesystem::readFile($path); + array_unshift($configs, array( + dirname($path), + phutil_ini_decode($config), + )); + } + + return $configs; + } + +} diff --git a/src/parser/__tests__/PhutilEditorConfigTestCase.php b/src/parser/__tests__/PhutilEditorConfigTestCase.php new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/PhutilEditorConfigTestCase.php @@ -0,0 +1,34 @@ + array( + 'indent_style' => 'space', + 'indent_size' => 2, + 'charset' => 'utf-8', + 'trim_trailing_whitespace' => 1, // This should be true, but PHP. + 'insert_final_newline' => 1, + ), + ); + + foreach ($tests as $path => $config) { + foreach ($config as $key => $value) { + $this->assertEqual( + $value, + $parser->getConfig($this->getTestFile($path), $key)); + } + } + } + + private function getTestFile($path) { + return dirname(__FILE__).'/editorconfig/'.$path; + } + +} diff --git a/src/parser/__tests__/editorconfig/.editorconfig b/src/parser/__tests__/editorconfig/.editorconfig new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/editorconfig/.editorconfig @@ -0,0 +1,6 @@ +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true