diff --git a/scripts/utils/prosediff.php b/scripts/utils/prosediff.php deleted file mode 100755 index e02c9c8..0000000 --- a/scripts/utils/prosediff.php +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env php -setTagline(pht('show prose differences')); -$args->setSynopsis(<<parseStandardArguments(); -$args->parse( - array( - array( - 'name' => 'files', - 'wildcard' => true, - ), - )); - -$files = $args->getArg('files'); -if (count($files) !== 2) { - $args->printHelpAndExit(); -} -$old_file = head($files); -$new_file = last($files); - -$old_data = Filesystem::readFile($old_file); -$new_data = Filesystem::readFile($new_file); - -$engine = new PhutilProseDifferenceEngine(); - -$prose_diff = $engine->getDiff($old_data, $new_data); - -foreach ($prose_diff->getParts() as $part) { - switch ($part['type']) { - case '-': - echo tsprintf('%B', $part['text']); - break; - case '+': - echo tsprintf('%B', $part['text']); - break; - case '=': - echo tsprintf('%B', $part['text']); - break; - } -} diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index a06d240..d61b6a1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,943 +1,937 @@ 2, 'class' => array( 'AASTNode' => 'parser/aast/api/AASTNode.php', 'AASTNodeList' => 'parser/aast/api/AASTNodeList.php', 'AASTToken' => 'parser/aast/api/AASTToken.php', 'AASTTree' => 'parser/aast/api/AASTTree.php', 'AbstractDirectedGraph' => 'utils/AbstractDirectedGraph.php', 'AbstractDirectedGraphTestCase' => 'utils/__tests__/AbstractDirectedGraphTestCase.php', 'AphrontHTTPHeaderParser' => 'aphront/headerparser/AphrontHTTPHeaderParser.php', 'AphrontHTTPHeaderParserTestCase' => 'aphront/headerparser/__tests__/AphrontHTTPHeaderParserTestCase.php', 'AphrontMultipartParser' => 'aphront/multipartparser/AphrontMultipartParser.php', 'AphrontMultipartParserTestCase' => 'aphront/multipartparser/__tests__/AphrontMultipartParserTestCase.php', 'AphrontMultipartPart' => 'aphront/multipartparser/AphrontMultipartPart.php', 'AphrontRequestStream' => 'aphront/requeststream/AphrontRequestStream.php', 'AphrontScopedUnguardedWriteCapability' => 'aphront/writeguard/AphrontScopedUnguardedWriteCapability.php', 'AphrontWriteGuard' => 'aphront/writeguard/AphrontWriteGuard.php', 'BaseHTTPFuture' => 'future/http/BaseHTTPFuture.php', 'CaseInsensitiveArray' => 'utils/CaseInsensitiveArray.php', 'CaseInsensitiveArrayTestCase' => 'utils/__tests__/CaseInsensitiveArrayTestCase.php', 'CommandException' => 'future/exec/CommandException.php', 'ConduitClient' => 'conduit/ConduitClient.php', 'ConduitClientException' => 'conduit/ConduitClientException.php', 'ConduitClientTestCase' => 'conduit/__tests__/ConduitClientTestCase.php', 'ConduitFuture' => 'conduit/ConduitFuture.php', 'ExecFuture' => 'future/exec/ExecFuture.php', 'ExecFutureTestCase' => 'future/exec/__tests__/ExecFutureTestCase.php', 'ExecPassthruTestCase' => 'future/exec/__tests__/ExecPassthruTestCase.php', 'FileFinder' => 'filesystem/FileFinder.php', 'FileFinderTestCase' => 'filesystem/__tests__/FileFinderTestCase.php', 'FileList' => 'filesystem/FileList.php', 'Filesystem' => 'filesystem/Filesystem.php', 'FilesystemException' => 'filesystem/FilesystemException.php', 'FilesystemTestCase' => 'filesystem/__tests__/FilesystemTestCase.php', 'Future' => 'future/Future.php', 'FutureIterator' => 'future/FutureIterator.php', 'FutureIteratorTestCase' => 'future/__tests__/FutureIteratorTestCase.php', 'FutureProxy' => 'future/FutureProxy.php', 'HTTPFuture' => 'future/http/HTTPFuture.php', 'HTTPFutureCURLResponseStatus' => 'future/http/status/HTTPFutureCURLResponseStatus.php', 'HTTPFutureCertificateResponseStatus' => 'future/http/status/HTTPFutureCertificateResponseStatus.php', 'HTTPFutureHTTPResponseStatus' => 'future/http/status/HTTPFutureHTTPResponseStatus.php', 'HTTPFutureParseResponseStatus' => 'future/http/status/HTTPFutureParseResponseStatus.php', 'HTTPFutureResponseStatus' => 'future/http/status/HTTPFutureResponseStatus.php', 'HTTPFutureTransportResponseStatus' => 'future/http/status/HTTPFutureTransportResponseStatus.php', 'HTTPSFuture' => 'future/http/HTTPSFuture.php', 'ImmediateFuture' => 'future/ImmediateFuture.php', 'LibphutilUSEnglishTranslation' => 'internationalization/translation/LibphutilUSEnglishTranslation.php', 'LinesOfALarge' => 'filesystem/linesofalarge/LinesOfALarge.php', 'LinesOfALargeExecFuture' => 'filesystem/linesofalarge/LinesOfALargeExecFuture.php', 'LinesOfALargeExecFutureTestCase' => 'filesystem/linesofalarge/__tests__/LinesOfALargeExecFutureTestCase.php', 'LinesOfALargeFile' => 'filesystem/linesofalarge/LinesOfALargeFile.php', 'LinesOfALargeFileTestCase' => 'filesystem/linesofalarge/__tests__/LinesOfALargeFileTestCase.php', 'MFilterTestHelper' => 'utils/__tests__/MFilterTestHelper.php', 'PHPASTParserTestCase' => 'parser/xhpast/__tests__/PHPASTParserTestCase.php', 'PhageAction' => 'phage/action/PhageAction.php', 'PhageAgentAction' => 'phage/action/PhageAgentAction.php', 'PhageAgentBootloader' => 'phage/bootloader/PhageAgentBootloader.php', 'PhageAgentTestCase' => 'phage/__tests__/PhageAgentTestCase.php', 'PhageExecuteAction' => 'phage/action/PhageExecuteAction.php', 'PhageLocalAction' => 'phage/action/PhageLocalAction.php', 'PhagePHPAgent' => 'phage/agent/PhagePHPAgent.php', 'PhagePHPAgentBootloader' => 'phage/bootloader/PhagePHPAgentBootloader.php', 'PhagePlanAction' => 'phage/action/PhagePlanAction.php', 'Phobject' => 'object/Phobject.php', 'PhobjectTestCase' => 'object/__tests__/PhobjectTestCase.php', 'PhutilAPCKeyValueCache' => 'cache/PhutilAPCKeyValueCache.php', 'PhutilAWSCloudFormationFuture' => 'future/aws/PhutilAWSCloudFormationFuture.php', 'PhutilAWSCloudWatchFuture' => 'future/aws/PhutilAWSCloudWatchFuture.php', 'PhutilAWSEC2Future' => 'future/aws/PhutilAWSEC2Future.php', 'PhutilAWSException' => 'future/aws/PhutilAWSException.php', 'PhutilAWSFuture' => 'future/aws/PhutilAWSFuture.php', 'PhutilAWSManagementWorkflow' => 'future/aws/management/PhutilAWSManagementWorkflow.php', 'PhutilAWSS3DeleteManagementWorkflow' => 'future/aws/management/PhutilAWSS3DeleteManagementWorkflow.php', 'PhutilAWSS3Future' => 'future/aws/PhutilAWSS3Future.php', 'PhutilAWSS3GetManagementWorkflow' => 'future/aws/management/PhutilAWSS3GetManagementWorkflow.php', 'PhutilAWSS3ManagementWorkflow' => 'future/aws/management/PhutilAWSS3ManagementWorkflow.php', 'PhutilAWSS3PutManagementWorkflow' => 'future/aws/management/PhutilAWSS3PutManagementWorkflow.php', 'PhutilAWSv4Signature' => 'future/aws/PhutilAWSv4Signature.php', 'PhutilAWSv4SignatureTestCase' => 'future/aws/__tests__/PhutilAWSv4SignatureTestCase.php', 'PhutilAggregateException' => 'error/PhutilAggregateException.php', 'PhutilAllCapsEnglishLocale' => 'internationalization/locales/PhutilAllCapsEnglishLocale.php', 'PhutilArgumentParser' => 'parser/argument/PhutilArgumentParser.php', 'PhutilArgumentParserException' => 'parser/argument/exception/PhutilArgumentParserException.php', 'PhutilArgumentParserTestCase' => 'parser/argument/__tests__/PhutilArgumentParserTestCase.php', 'PhutilArgumentSpecification' => 'parser/argument/PhutilArgumentSpecification.php', 'PhutilArgumentSpecificationException' => 'parser/argument/exception/PhutilArgumentSpecificationException.php', 'PhutilArgumentSpecificationTestCase' => 'parser/argument/__tests__/PhutilArgumentSpecificationTestCase.php', 'PhutilArgumentSpellingCorrector' => 'parser/argument/PhutilArgumentSpellingCorrector.php', 'PhutilArgumentSpellingCorrectorTestCase' => 'parser/argument/__tests__/PhutilArgumentSpellingCorrectorTestCase.php', 'PhutilArgumentUsageException' => 'parser/argument/exception/PhutilArgumentUsageException.php', 'PhutilArgumentWorkflow' => 'parser/argument/workflow/PhutilArgumentWorkflow.php', 'PhutilArray' => 'utils/PhutilArray.php', 'PhutilArrayTestCase' => 'utils/__tests__/PhutilArrayTestCase.php', 'PhutilArrayWithDefaultValue' => 'utils/PhutilArrayWithDefaultValue.php', 'PhutilAsanaFuture' => 'future/asana/PhutilAsanaFuture.php', 'PhutilBacktraceSignalHandler' => 'future/exec/PhutilBacktraceSignalHandler.php', 'PhutilBallOfPHP' => 'phage/util/PhutilBallOfPHP.php', 'PhutilBinaryAnalyzer' => 'filesystem/binary/PhutilBinaryAnalyzer.php', 'PhutilBinaryAnalyzerTestCase' => 'filesystem/binary/__tests__/PhutilBinaryAnalyzerTestCase.php', 'PhutilBootloader' => 'moduleutils/PhutilBootloader.php', 'PhutilBootloaderException' => 'moduleutils/PhutilBootloaderException.php', 'PhutilBritishEnglishLocale' => 'internationalization/locales/PhutilBritishEnglishLocale.php', 'PhutilBufferedIterator' => 'utils/PhutilBufferedIterator.php', 'PhutilBufferedIteratorTestCase' => 'utils/__tests__/PhutilBufferedIteratorTestCase.php', 'PhutilBugtraqParser' => 'parser/PhutilBugtraqParser.php', 'PhutilBugtraqParserTestCase' => 'parser/__tests__/PhutilBugtraqParserTestCase.php', 'PhutilCIDRBlock' => 'ip/PhutilCIDRBlock.php', 'PhutilCIDRList' => 'ip/PhutilCIDRList.php', 'PhutilCallbackFilterIterator' => 'utils/PhutilCallbackFilterIterator.php', 'PhutilCallbackSignalHandler' => 'future/exec/PhutilCallbackSignalHandler.php', 'PhutilChannel' => 'channel/PhutilChannel.php', 'PhutilChannelChannel' => 'channel/PhutilChannelChannel.php', 'PhutilChannelTestCase' => 'channel/__tests__/PhutilChannelTestCase.php', 'PhutilChunkedIterator' => 'utils/PhutilChunkedIterator.php', 'PhutilChunkedIteratorTestCase' => 'utils/__tests__/PhutilChunkedIteratorTestCase.php', 'PhutilClassMapQuery' => 'symbols/PhutilClassMapQuery.php', 'PhutilCloudWatchMetric' => 'future/aws/PhutilCloudWatchMetric.php', 'PhutilCommandString' => 'xsprintf/PhutilCommandString.php', 'PhutilConsole' => 'console/PhutilConsole.php', 'PhutilConsoleBlock' => 'console/view/PhutilConsoleBlock.php', 'PhutilConsoleError' => 'console/view/PhutilConsoleError.php', 'PhutilConsoleFormatter' => 'console/PhutilConsoleFormatter.php', 'PhutilConsoleInfo' => 'console/view/PhutilConsoleInfo.php', 'PhutilConsoleList' => 'console/view/PhutilConsoleList.php', 'PhutilConsoleLogLine' => 'console/view/PhutilConsoleLogLine.php', 'PhutilConsoleMessage' => 'console/PhutilConsoleMessage.php', 'PhutilConsoleMetrics' => 'console/PhutilConsoleMetrics.php', 'PhutilConsoleMetricsSignalHandler' => 'future/exec/PhutilConsoleMetricsSignalHandler.php', 'PhutilConsoleProgressBar' => 'console/PhutilConsoleProgressBar.php', 'PhutilConsoleProgressSink' => 'progress/PhutilConsoleProgressSink.php', 'PhutilConsoleServer' => 'console/PhutilConsoleServer.php', 'PhutilConsoleServerChannel' => 'console/PhutilConsoleServerChannel.php', 'PhutilConsoleSkip' => 'console/view/PhutilConsoleSkip.php', 'PhutilConsoleStdinNotInteractiveException' => 'console/PhutilConsoleStdinNotInteractiveException.php', 'PhutilConsoleSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilConsoleSyntaxHighlighter.php', 'PhutilConsoleTable' => 'console/view/PhutilConsoleTable.php', 'PhutilConsoleView' => 'console/view/PhutilConsoleView.php', 'PhutilConsoleWarning' => 'console/view/PhutilConsoleWarning.php', 'PhutilConsoleWrapTestCase' => 'console/__tests__/PhutilConsoleWrapTestCase.php', 'PhutilContextFreeGrammar' => 'grammar/PhutilContextFreeGrammar.php', 'PhutilCowsay' => 'utils/PhutilCowsay.php', 'PhutilCowsayTestCase' => 'utils/__tests__/PhutilCowsayTestCase.php', 'PhutilCsprintfTestCase' => 'xsprintf/__tests__/PhutilCsprintfTestCase.php', 'PhutilCzechLocale' => 'internationalization/locales/PhutilCzechLocale.php', 'PhutilDOMNode' => 'parser/html/PhutilDOMNode.php', 'PhutilDaemon' => 'daemon/PhutilDaemon.php', 'PhutilDaemonHandle' => 'daemon/PhutilDaemonHandle.php', 'PhutilDaemonOverseer' => 'daemon/PhutilDaemonOverseer.php', 'PhutilDaemonOverseerModule' => 'daemon/PhutilDaemonOverseerModule.php', 'PhutilDaemonPool' => 'daemon/PhutilDaemonPool.php', 'PhutilDefaultSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilDefaultSyntaxHighlighter.php', 'PhutilDefaultSyntaxHighlighterEngine' => 'markup/syntax/engine/PhutilDefaultSyntaxHighlighterEngine.php', 'PhutilDefaultSyntaxHighlighterEnginePygmentsFuture' => 'markup/syntax/highlighter/pygments/PhutilDefaultSyntaxHighlighterEnginePygmentsFuture.php', 'PhutilDefaultSyntaxHighlighterEngineTestCase' => 'markup/syntax/engine/__tests__/PhutilDefaultSyntaxHighlighterEngineTestCase.php', 'PhutilDeferredLog' => 'filesystem/PhutilDeferredLog.php', 'PhutilDeferredLogTestCase' => 'filesystem/__tests__/PhutilDeferredLogTestCase.php', 'PhutilDiffBinaryAnalyzer' => 'filesystem/binary/PhutilDiffBinaryAnalyzer.php', 'PhutilDirectedScalarGraph' => 'utils/PhutilDirectedScalarGraph.php', 'PhutilDirectoryFixture' => 'filesystem/PhutilDirectoryFixture.php', 'PhutilDirectoryKeyValueCache' => 'cache/PhutilDirectoryKeyValueCache.php', 'PhutilDivinerSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilDivinerSyntaxHighlighter.php', 'PhutilDocblockParser' => 'parser/PhutilDocblockParser.php', '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', 'PhutilEmojiLocale' => 'internationalization/locales/PhutilEmojiLocale.php', 'PhutilEnglishCanadaLocale' => 'internationalization/locales/PhutilEnglishCanadaLocale.php', 'PhutilErrorHandler' => 'error/PhutilErrorHandler.php', 'PhutilErrorHandlerTestCase' => 'error/__tests__/PhutilErrorHandlerTestCase.php', 'PhutilErrorTrap' => 'error/PhutilErrorTrap.php', 'PhutilEvent' => 'events/PhutilEvent.php', 'PhutilEventConstants' => 'events/constant/PhutilEventConstants.php', 'PhutilEventEngine' => 'events/PhutilEventEngine.php', 'PhutilEventListener' => 'events/PhutilEventListener.php', 'PhutilEventType' => 'events/constant/PhutilEventType.php', 'PhutilExampleBufferedIterator' => 'utils/PhutilExampleBufferedIterator.php', 'PhutilExcessiveServiceCallsDaemon' => 'daemon/torture/PhutilExcessiveServiceCallsDaemon.php', 'PhutilExecChannel' => 'channel/PhutilExecChannel.php', 'PhutilExecPassthru' => 'future/exec/PhutilExecPassthru.php', 'PhutilExecutableFuture' => 'future/exec/PhutilExecutableFuture.php', 'PhutilExecutionEnvironment' => 'utils/PhutilExecutionEnvironment.php', 'PhutilExtensionsTestCase' => 'moduleutils/__tests__/PhutilExtensionsTestCase.php', 'PhutilFatalDaemon' => 'daemon/torture/PhutilFatalDaemon.php', 'PhutilFileLock' => 'filesystem/PhutilFileLock.php', 'PhutilFileLockTestCase' => 'filesystem/__tests__/PhutilFileLockTestCase.php', 'PhutilFileTree' => 'filesystem/PhutilFileTree.php', 'PhutilFrenchLocale' => 'internationalization/locales/PhutilFrenchLocale.php', 'PhutilGermanLocale' => 'internationalization/locales/PhutilGermanLocale.php', 'PhutilGitBinaryAnalyzer' => 'filesystem/binary/PhutilGitBinaryAnalyzer.php', 'PhutilGitHubFuture' => 'future/github/PhutilGitHubFuture.php', 'PhutilGitHubResponse' => 'future/github/PhutilGitHubResponse.php', 'PhutilGitURI' => 'parser/PhutilGitURI.php', 'PhutilGitURITestCase' => 'parser/__tests__/PhutilGitURITestCase.php', 'PhutilHTMLParser' => 'parser/html/PhutilHTMLParser.php', 'PhutilHTMLParserTestCase' => 'parser/html/__tests__/PhutilHTMLParserTestCase.php', 'PhutilHTTPEngineExtension' => 'future/http/PhutilHTTPEngineExtension.php', 'PhutilHTTPResponse' => 'parser/http/PhutilHTTPResponse.php', 'PhutilHTTPResponseParser' => 'parser/http/PhutilHTTPResponseParser.php', 'PhutilHTTPResponseParserTestCase' => 'parser/http/__tests__/PhutilHTTPResponseParserTestCase.php', 'PhutilHangForeverDaemon' => 'daemon/torture/PhutilHangForeverDaemon.php', 'PhutilHashingIterator' => 'utils/PhutilHashingIterator.php', 'PhutilHashingIteratorTestCase' => 'utils/__tests__/PhutilHashingIteratorTestCase.php', 'PhutilHelpArgumentWorkflow' => 'parser/argument/workflow/PhutilHelpArgumentWorkflow.php', 'PhutilHgsprintfTestCase' => 'xsprintf/__tests__/PhutilHgsprintfTestCase.php', 'PhutilHighIntensityIntervalDaemon' => 'daemon/torture/PhutilHighIntensityIntervalDaemon.php', 'PhutilINIParserException' => 'parser/exception/PhutilINIParserException.php', 'PhutilIPAddress' => 'ip/PhutilIPAddress.php', 'PhutilIPAddressTestCase' => 'ip/__tests__/PhutilIPAddressTestCase.php', 'PhutilIPv4Address' => 'ip/PhutilIPv4Address.php', 'PhutilIPv6Address' => 'ip/PhutilIPv6Address.php', 'PhutilInRequestKeyValueCache' => 'cache/PhutilInRequestKeyValueCache.php', 'PhutilInteractiveEditor' => 'console/PhutilInteractiveEditor.php', 'PhutilInvalidRuleParserGeneratorException' => 'parser/generator/exception/PhutilInvalidRuleParserGeneratorException.php', 'PhutilInvalidStateException' => 'exception/PhutilInvalidStateException.php', 'PhutilInvalidStateExceptionTestCase' => 'exception/__tests__/PhutilInvalidStateExceptionTestCase.php', 'PhutilInvisibleSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilInvisibleSyntaxHighlighter.php', 'PhutilIrreducibleRuleParserGeneratorException' => 'parser/generator/exception/PhutilIrreducibleRuleParserGeneratorException.php', 'PhutilJSON' => 'parser/PhutilJSON.php', 'PhutilJSONFragmentLexer' => 'lexer/PhutilJSONFragmentLexer.php', 'PhutilJSONFragmentLexerHighlighterTestCase' => 'markup/syntax/highlighter/__tests__/PhutilJSONFragmentLexerHighlighterTestCase.php', 'PhutilJSONParser' => 'parser/PhutilJSONParser.php', 'PhutilJSONParserException' => 'parser/exception/PhutilJSONParserException.php', 'PhutilJSONParserTestCase' => 'parser/__tests__/PhutilJSONParserTestCase.php', 'PhutilJSONProtocolChannel' => 'channel/PhutilJSONProtocolChannel.php', 'PhutilJSONProtocolChannelTestCase' => 'channel/__tests__/PhutilJSONProtocolChannelTestCase.php', 'PhutilJSONTestCase' => 'parser/__tests__/PhutilJSONTestCase.php', 'PhutilJavaFragmentLexer' => 'lexer/PhutilJavaFragmentLexer.php', 'PhutilKeyValueCache' => 'cache/PhutilKeyValueCache.php', 'PhutilKeyValueCacheNamespace' => 'cache/PhutilKeyValueCacheNamespace.php', 'PhutilKeyValueCacheProfiler' => 'cache/PhutilKeyValueCacheProfiler.php', 'PhutilKeyValueCacheProxy' => 'cache/PhutilKeyValueCacheProxy.php', 'PhutilKeyValueCacheStack' => 'cache/PhutilKeyValueCacheStack.php', 'PhutilKeyValueCacheTestCase' => 'cache/__tests__/PhutilKeyValueCacheTestCase.php', 'PhutilKoreanLocale' => 'internationalization/locales/PhutilKoreanLocale.php', 'PhutilLanguageGuesser' => 'parser/PhutilLanguageGuesser.php', 'PhutilLanguageGuesserTestCase' => 'parser/__tests__/PhutilLanguageGuesserTestCase.php', 'PhutilLexer' => 'lexer/PhutilLexer.php', 'PhutilLexerSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilLexerSyntaxHighlighter.php', 'PhutilLibraryConflictException' => 'moduleutils/PhutilLibraryConflictException.php', 'PhutilLibraryMapBuilder' => 'moduleutils/PhutilLibraryMapBuilder.php', 'PhutilLibraryTestCase' => '__tests__/PhutilLibraryTestCase.php', 'PhutilLocale' => 'internationalization/PhutilLocale.php', 'PhutilLocaleTestCase' => 'internationalization/__tests__/PhutilLocaleTestCase.php', 'PhutilLock' => 'filesystem/PhutilLock.php', 'PhutilLockException' => 'filesystem/PhutilLockException.php', 'PhutilLogFileChannel' => 'channel/PhutilLogFileChannel.php', 'PhutilLunarPhase' => 'utils/PhutilLunarPhase.php', 'PhutilLunarPhaseTestCase' => 'utils/__tests__/PhutilLunarPhaseTestCase.php', 'PhutilMarkupEngine' => 'markup/PhutilMarkupEngine.php', 'PhutilMarkupTestCase' => 'markup/__tests__/PhutilMarkupTestCase.php', 'PhutilMemcacheKeyValueCache' => 'cache/PhutilMemcacheKeyValueCache.php', 'PhutilMercurialBinaryAnalyzer' => 'filesystem/binary/PhutilMercurialBinaryAnalyzer.php', 'PhutilMethodNotImplementedException' => 'error/PhutilMethodNotImplementedException.php', 'PhutilMetricsChannel' => 'channel/PhutilMetricsChannel.php', 'PhutilMissingSymbolException' => 'symbols/exception/PhutilMissingSymbolException.php', 'PhutilModuleUtilsTestCase' => 'moduleutils/__tests__/PhutilModuleUtilsTestCase.php', 'PhutilNiceDaemon' => 'daemon/torture/PhutilNiceDaemon.php', 'PhutilNumber' => 'internationalization/PhutilNumber.php', 'PhutilOAuth1Future' => 'future/oauth/PhutilOAuth1Future.php', 'PhutilOAuth1FutureTestCase' => 'future/oauth/__tests__/PhutilOAuth1FutureTestCase.php', 'PhutilOnDiskKeyValueCache' => 'cache/PhutilOnDiskKeyValueCache.php', 'PhutilOpaqueEnvelope' => 'error/PhutilOpaqueEnvelope.php', 'PhutilOpaqueEnvelopeKey' => 'error/PhutilOpaqueEnvelopeKey.php', 'PhutilOpaqueEnvelopeTestCase' => 'error/__tests__/PhutilOpaqueEnvelopeTestCase.php', 'PhutilPHPFragmentLexer' => 'lexer/PhutilPHPFragmentLexer.php', 'PhutilPHPFragmentLexerHighlighterTestCase' => 'markup/syntax/highlighter/__tests__/PhutilPHPFragmentLexerHighlighterTestCase.php', 'PhutilPHPFragmentLexerTestCase' => 'lexer/__tests__/PhutilPHPFragmentLexerTestCase.php', 'PhutilPHPObjectProtocolChannel' => 'channel/PhutilPHPObjectProtocolChannel.php', 'PhutilPHPObjectProtocolChannelTestCase' => 'channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php', 'PhutilParserGenerator' => 'parser/PhutilParserGenerator.php', 'PhutilParserGeneratorException' => 'parser/generator/exception/PhutilParserGeneratorException.php', 'PhutilParserGeneratorTestCase' => 'parser/__tests__/PhutilParserGeneratorTestCase.php', 'PhutilPayPalAPIFuture' => 'future/paypal/PhutilPayPalAPIFuture.php', 'PhutilPerson' => 'internationalization/PhutilPerson.php', 'PhutilPersonTest' => 'internationalization/__tests__/PhutilPersonTest.php', 'PhutilPhtTestCase' => 'internationalization/__tests__/PhutilPhtTestCase.php', 'PhutilPirateEnglishLocale' => 'internationalization/locales/PhutilPirateEnglishLocale.php', 'PhutilPortugueseBrazilLocale' => 'internationalization/locales/PhutilPortugueseBrazilLocale.php', 'PhutilPortuguesePortugalLocale' => 'internationalization/locales/PhutilPortuguesePortugalLocale.php', 'PhutilPostmarkFuture' => 'future/postmark/PhutilPostmarkFuture.php', 'PhutilPregsprintfTestCase' => 'xsprintf/__tests__/PhutilPregsprintfTestCase.php', 'PhutilProcessGroupDaemon' => 'daemon/torture/PhutilProcessGroupDaemon.php', 'PhutilProcessQuery' => 'filesystem/PhutilProcessQuery.php', 'PhutilProcessRef' => 'filesystem/PhutilProcessRef.php', 'PhutilProcessRefTestCase' => 'filesystem/__tests__/PhutilProcessRefTestCase.php', 'PhutilProgressSink' => 'progress/PhutilProgressSink.php', - 'PhutilProseDiff' => 'utils/PhutilProseDiff.php', - 'PhutilProseDiffTestCase' => 'utils/__tests__/PhutilProseDiffTestCase.php', - 'PhutilProseDifferenceEngine' => 'utils/PhutilProseDifferenceEngine.php', 'PhutilProtocolChannel' => 'channel/PhutilProtocolChannel.php', 'PhutilProxyException' => 'error/PhutilProxyException.php', 'PhutilProxyIterator' => 'utils/PhutilProxyIterator.php', 'PhutilPygmentizeBinaryAnalyzer' => 'filesystem/binary/PhutilPygmentizeBinaryAnalyzer.php', 'PhutilPygmentizeParser' => 'parser/PhutilPygmentizeParser.php', 'PhutilPygmentizeParserTestCase' => 'parser/__tests__/PhutilPygmentizeParserTestCase.php', 'PhutilPygmentsSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilPygmentsSyntaxHighlighter.php', 'PhutilPythonFragmentLexer' => 'lexer/PhutilPythonFragmentLexer.php', 'PhutilQueryStringParser' => 'parser/PhutilQueryStringParser.php', 'PhutilQueryStringParserTestCase' => 'parser/__tests__/PhutilQueryStringParserTestCase.php', 'PhutilRainbowSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilRainbowSyntaxHighlighter.php', 'PhutilRawEnglishLocale' => 'internationalization/locales/PhutilRawEnglishLocale.php', 'PhutilReadableSerializer' => 'readableserializer/PhutilReadableSerializer.php', 'PhutilReadableSerializerTestCase' => 'readableserializer/__tests__/PhutilReadableSerializerTestCase.php', 'PhutilRope' => 'utils/PhutilRope.php', 'PhutilRopeTestCase' => 'utils/__tests__/PhutilRopeTestCase.php', 'PhutilSafeHTML' => 'markup/PhutilSafeHTML.php', 'PhutilSafeHTMLProducerInterface' => 'markup/PhutilSafeHTMLProducerInterface.php', 'PhutilSafeHTMLTestCase' => 'markup/__tests__/PhutilSafeHTMLTestCase.php', 'PhutilSaturateStdoutDaemon' => 'daemon/torture/PhutilSaturateStdoutDaemon.php', 'PhutilSearchQueryCompiler' => 'search/PhutilSearchQueryCompiler.php', 'PhutilSearchQueryCompilerSyntaxException' => 'search/PhutilSearchQueryCompilerSyntaxException.php', 'PhutilSearchQueryCompilerTestCase' => 'search/__tests__/PhutilSearchQueryCompilerTestCase.php', 'PhutilSearchQueryToken' => 'search/PhutilSearchQueryToken.php', 'PhutilSearchStemmer' => 'search/PhutilSearchStemmer.php', 'PhutilSearchStemmerTestCase' => 'search/__tests__/PhutilSearchStemmerTestCase.php', 'PhutilServiceProfiler' => 'serviceprofiler/PhutilServiceProfiler.php', 'PhutilShellLexer' => 'lexer/PhutilShellLexer.php', 'PhutilShellLexerTestCase' => 'lexer/__tests__/PhutilShellLexerTestCase.php', 'PhutilSignalHandler' => 'future/exec/PhutilSignalHandler.php', 'PhutilSignalRouter' => 'future/exec/PhutilSignalRouter.php', 'PhutilSimpleOptions' => 'parser/PhutilSimpleOptions.php', 'PhutilSimpleOptionsLexer' => 'lexer/PhutilSimpleOptionsLexer.php', 'PhutilSimpleOptionsLexerTestCase' => 'lexer/__tests__/PhutilSimpleOptionsLexerTestCase.php', 'PhutilSimpleOptionsTestCase' => 'parser/__tests__/PhutilSimpleOptionsTestCase.php', 'PhutilSimplifiedChineseLocale' => 'internationalization/locales/PhutilSimplifiedChineseLocale.php', 'PhutilSlackFuture' => 'future/slack/PhutilSlackFuture.php', 'PhutilSocketChannel' => 'channel/PhutilSocketChannel.php', 'PhutilSortVector' => 'utils/PhutilSortVector.php', 'PhutilSpanishSpainLocale' => 'internationalization/locales/PhutilSpanishSpainLocale.php', 'PhutilSprite' => 'sprites/PhutilSprite.php', 'PhutilSpriteSheet' => 'sprites/PhutilSpriteSheet.php', 'PhutilStreamIterator' => 'utils/PhutilStreamIterator.php', 'PhutilSubversionBinaryAnalyzer' => 'filesystem/binary/PhutilSubversionBinaryAnalyzer.php', 'PhutilSymbolLoader' => 'symbols/PhutilSymbolLoader.php', 'PhutilSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilSyntaxHighlighter.php', 'PhutilSyntaxHighlighterEngine' => 'markup/syntax/engine/PhutilSyntaxHighlighterEngine.php', 'PhutilSyntaxHighlighterException' => 'markup/syntax/highlighter/PhutilSyntaxHighlighterException.php', 'PhutilSystem' => 'utils/PhutilSystem.php', 'PhutilSystemTestCase' => 'utils/__tests__/PhutilSystemTestCase.php', 'PhutilTerminalString' => 'xsprintf/PhutilTerminalString.php', 'PhutilTestPhobject' => 'object/__tests__/PhutilTestPhobject.php', 'PhutilTortureTestDaemon' => 'daemon/torture/PhutilTortureTestDaemon.php', 'PhutilTraditionalChineseLocale' => 'internationalization/locales/PhutilTraditionalChineseLocale.php', 'PhutilTranslation' => 'internationalization/PhutilTranslation.php', 'PhutilTranslationTestCase' => 'internationalization/__tests__/PhutilTranslationTestCase.php', 'PhutilTranslator' => 'internationalization/PhutilTranslator.php', 'PhutilTranslatorTestCase' => 'internationalization/__tests__/PhutilTranslatorTestCase.php', 'PhutilTsprintfTestCase' => 'xsprintf/__tests__/PhutilTsprintfTestCase.php', 'PhutilTwitchFuture' => 'future/twitch/PhutilTwitchFuture.php', 'PhutilTypeCheckException' => 'parser/exception/PhutilTypeCheckException.php', 'PhutilTypeExtraParametersException' => 'parser/exception/PhutilTypeExtraParametersException.php', 'PhutilTypeLexer' => 'lexer/PhutilTypeLexer.php', 'PhutilTypeMissingParametersException' => 'parser/exception/PhutilTypeMissingParametersException.php', 'PhutilTypeSpec' => 'parser/PhutilTypeSpec.php', 'PhutilTypeSpecTestCase' => 'parser/__tests__/PhutilTypeSpecTestCase.php', 'PhutilURI' => 'parser/PhutilURI.php', 'PhutilURITestCase' => 'parser/__tests__/PhutilURITestCase.php', 'PhutilUSEnglishLocale' => 'internationalization/locales/PhutilUSEnglishLocale.php', 'PhutilUTF8StringTruncator' => 'utils/PhutilUTF8StringTruncator.php', 'PhutilUTF8TestCase' => 'utils/__tests__/PhutilUTF8TestCase.php', 'PhutilUnknownSymbolParserGeneratorException' => 'parser/generator/exception/PhutilUnknownSymbolParserGeneratorException.php', 'PhutilUnreachableRuleParserGeneratorException' => 'parser/generator/exception/PhutilUnreachableRuleParserGeneratorException.php', 'PhutilUnreachableTerminalParserGeneratorException' => 'parser/generator/exception/PhutilUnreachableTerminalParserGeneratorException.php', 'PhutilUrisprintfTestCase' => 'xsprintf/__tests__/PhutilUrisprintfTestCase.php', 'PhutilUtilsTestCase' => 'utils/__tests__/PhutilUtilsTestCase.php', 'PhutilVeryWowEnglishLocale' => 'internationalization/locales/PhutilVeryWowEnglishLocale.php', 'PhutilWordPressFuture' => 'future/wordpress/PhutilWordPressFuture.php', 'PhutilXHPASTBinary' => 'parser/xhpast/bin/PhutilXHPASTBinary.php', 'PhutilXHPASTSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilXHPASTSyntaxHighlighter.php', 'PhutilXHPASTSyntaxHighlighterFuture' => 'markup/syntax/highlighter/xhpast/PhutilXHPASTSyntaxHighlighterFuture.php', 'PhutilXHPASTSyntaxHighlighterTestCase' => 'markup/syntax/highlighter/__tests__/PhutilXHPASTSyntaxHighlighterTestCase.php', 'TempFile' => 'filesystem/TempFile.php', 'TestAbstractDirectedGraph' => 'utils/__tests__/TestAbstractDirectedGraph.php', 'XHPASTNode' => 'parser/xhpast/api/XHPASTNode.php', 'XHPASTNodeTestCase' => 'parser/xhpast/api/__tests__/XHPASTNodeTestCase.php', 'XHPASTSyntaxErrorException' => 'parser/xhpast/api/XHPASTSyntaxErrorException.php', 'XHPASTToken' => 'parser/xhpast/api/XHPASTToken.php', 'XHPASTTree' => 'parser/xhpast/api/XHPASTTree.php', 'XHPASTTreeTestCase' => 'parser/xhpast/api/__tests__/XHPASTTreeTestCase.php', 'XsprintfUnknownConversionException' => 'xsprintf/exception/XsprintfUnknownConversionException.php', ), 'function' => array( 'array_fuse' => 'utils/utils.php', 'array_interleave' => 'utils/utils.php', 'array_mergev' => 'utils/utils.php', 'array_select_keys' => 'utils/utils.php', 'assert_instances_of' => 'utils/utils.php', 'assert_same_keys' => 'utils/utils.php', 'assert_stringlike' => 'utils/utils.php', 'coalesce' => 'utils/utils.php', 'csprintf' => 'xsprintf/csprintf.php', 'exec_manual' => 'future/exec/execx.php', 'execx' => 'future/exec/execx.php', 'head' => 'utils/utils.php', 'head_key' => 'utils/utils.php', 'hgsprintf' => 'xsprintf/hgsprintf.php', 'hsprintf' => 'markup/render.php', 'id' => 'utils/utils.php', 'idx' => 'utils/utils.php', 'idxv' => 'utils/utils.php', 'ifilter' => 'utils/utils.php', 'igroup' => 'utils/utils.php', 'ipull' => 'utils/utils.php', 'isort' => 'utils/utils.php', 'jsprintf' => 'xsprintf/jsprintf.php', 'last' => 'utils/utils.php', 'last_key' => 'utils/utils.php', 'ldap_sprintf' => 'xsprintf/ldapsprintf.php', 'mfilter' => 'utils/utils.php', 'mgroup' => 'utils/utils.php', 'mpull' => 'utils/utils.php', 'msort' => 'utils/utils.php', 'msortv' => 'utils/utils.php', 'newv' => 'utils/utils.php', 'nonempty' => 'utils/utils.php', 'phlog' => 'error/phlog.php', 'pht' => 'internationalization/pht.php', 'phutil_build_http_querystring' => 'utils/utils.php', 'phutil_build_http_querystring_from_pairs' => 'utils/utils.php', 'phutil_censor_credentials' => 'utils/utils.php', 'phutil_console_confirm' => 'console/format.php', 'phutil_console_format' => 'console/format.php', 'phutil_console_get_terminal_width' => 'console/format.php', 'phutil_console_prompt' => 'console/format.php', 'phutil_console_require_tty' => 'console/format.php', 'phutil_console_select' => 'console/format.php', 'phutil_console_wrap' => 'console/format.php', 'phutil_count' => 'internationalization/pht.php', 'phutil_date_format' => 'utils/viewutils.php', 'phutil_decode_mime_header' => 'utils/utils.php', 'phutil_deprecated' => 'moduleutils/moduleutils.php', 'phutil_describe_type' => 'utils/utils.php', 'phutil_error_listener_example' => 'error/phlog.php', 'phutil_escape_html' => 'markup/render.php', 'phutil_escape_html_newlines' => 'markup/render.php', 'phutil_escape_uri' => 'markup/render.php', 'phutil_escape_uri_path_component' => 'markup/render.php', 'phutil_fnmatch' => 'utils/utils.php', 'phutil_format_bytes' => 'utils/viewutils.php', 'phutil_format_relative_time' => 'utils/viewutils.php', 'phutil_format_relative_time_detailed' => 'utils/viewutils.php', 'phutil_format_units_generic' => 'utils/viewutils.php', 'phutil_fwrite_nonblocking_stream' => 'utils/utils.php', 'phutil_get_current_library_name' => 'moduleutils/moduleutils.php', 'phutil_get_library_name_for_root' => 'moduleutils/moduleutils.php', 'phutil_get_library_root' => 'moduleutils/moduleutils.php', 'phutil_get_library_root_for_path' => 'moduleutils/moduleutils.php', 'phutil_get_signal_name' => 'future/exec/execx.php', 'phutil_get_system_locale' => 'utils/utf8.php', 'phutil_hashes_are_identical' => 'utils/utils.php', 'phutil_http_parameter_pair' => 'utils/utils.php', 'phutil_implode_html' => 'markup/render.php', 'phutil_ini_decode' => 'utils/utils.php', 'phutil_is_hiphop_runtime' => 'utils/utils.php', 'phutil_is_natural_list' => 'utils/utils.php', 'phutil_is_system_locale_available' => 'utils/utf8.php', 'phutil_is_utf8' => 'utils/utf8.php', 'phutil_is_utf8_slowly' => 'utils/utf8.php', 'phutil_is_utf8_with_only_bmp_characters' => 'utils/utf8.php', 'phutil_is_windows' => 'utils/utils.php', 'phutil_json_decode' => 'utils/utils.php', 'phutil_json_encode' => 'utils/utils.php', 'phutil_load_library' => 'moduleutils/core.php', 'phutil_loggable_string' => 'utils/utils.php', 'phutil_microseconds_since' => 'utils/utils.php', 'phutil_parse_bytes' => 'utils/viewutils.php', 'phutil_passthru' => 'future/exec/execx.php', 'phutil_person' => 'internationalization/pht.php', 'phutil_register_library' => 'moduleutils/core.php', 'phutil_register_library_map' => 'moduleutils/core.php', 'phutil_safe_html' => 'markup/render.php', 'phutil_set_system_locale' => 'utils/utf8.php', 'phutil_split_lines' => 'utils/utils.php', 'phutil_string_cast' => 'utils/utils.php', 'phutil_tag' => 'markup/render.php', 'phutil_tag_div' => 'markup/render.php', 'phutil_unescape_uri_path_component' => 'markup/render.php', 'phutil_units' => 'utils/utils.php', 'phutil_utf8_console_strlen' => 'utils/utf8.php', 'phutil_utf8_convert' => 'utils/utf8.php', 'phutil_utf8_encode_codepoint' => 'utils/utf8.php', 'phutil_utf8_hard_wrap' => 'utils/utf8.php', 'phutil_utf8_hard_wrap_html' => 'utils/utf8.php', 'phutil_utf8_is_cjk' => 'utils/utf8.php', 'phutil_utf8_is_combining_character' => 'utils/utf8.php', 'phutil_utf8_strlen' => 'utils/utf8.php', 'phutil_utf8_strtolower' => 'utils/utf8.php', 'phutil_utf8_strtoupper' => 'utils/utf8.php', 'phutil_utf8_strtr' => 'utils/utf8.php', 'phutil_utf8_ucwords' => 'utils/utf8.php', 'phutil_utf8ize' => 'utils/utf8.php', 'phutil_utf8v' => 'utils/utf8.php', 'phutil_utf8v_codepoints' => 'utils/utf8.php', 'phutil_utf8v_combine_characters' => 'utils/utf8.php', 'phutil_utf8v_combined' => 'utils/utf8.php', 'phutil_validate_json' => 'utils/utils.php', 'phutil_var_export' => 'utils/utils.php', 'ppull' => 'utils/utils.php', 'pregsprintf' => 'xsprintf/pregsprintf.php', 'tsprintf' => 'xsprintf/tsprintf.php', 'urisprintf' => 'xsprintf/urisprintf.php', 'vcsprintf' => 'xsprintf/csprintf.php', 'vjsprintf' => 'xsprintf/jsprintf.php', 'vurisprintf' => 'xsprintf/urisprintf.php', 'xhp_parser_node_constants' => 'parser/xhpast/parser_nodes.php', 'xhpast_parser_token_constants' => 'parser/xhpast/parser_tokens.php', 'xsprintf' => 'xsprintf/xsprintf.php', 'xsprintf_callback_example' => 'xsprintf/xsprintf.php', 'xsprintf_command' => 'xsprintf/csprintf.php', 'xsprintf_javascript' => 'xsprintf/jsprintf.php', 'xsprintf_ldap' => 'xsprintf/ldapsprintf.php', 'xsprintf_mercurial' => 'xsprintf/hgsprintf.php', 'xsprintf_regex' => 'xsprintf/pregsprintf.php', 'xsprintf_terminal' => 'xsprintf/tsprintf.php', 'xsprintf_uri' => 'xsprintf/urisprintf.php', ), 'xmap' => array( 'AASTNode' => 'Phobject', 'AASTNodeList' => array( 'Phobject', 'Countable', 'Iterator', ), 'AASTToken' => 'Phobject', 'AASTTree' => 'Phobject', 'AbstractDirectedGraph' => 'Phobject', 'AbstractDirectedGraphTestCase' => 'PhutilTestCase', 'AphrontHTTPHeaderParser' => 'Phobject', 'AphrontHTTPHeaderParserTestCase' => 'PhutilTestCase', 'AphrontMultipartParser' => 'Phobject', 'AphrontMultipartParserTestCase' => 'PhutilTestCase', 'AphrontMultipartPart' => 'Phobject', 'AphrontRequestStream' => 'Phobject', 'AphrontScopedUnguardedWriteCapability' => 'Phobject', 'AphrontWriteGuard' => 'Phobject', 'BaseHTTPFuture' => 'Future', 'CaseInsensitiveArray' => 'PhutilArray', 'CaseInsensitiveArrayTestCase' => 'PhutilTestCase', 'CommandException' => 'Exception', 'ConduitClient' => 'Phobject', 'ConduitClientException' => 'Exception', 'ConduitClientTestCase' => 'PhutilTestCase', 'ConduitFuture' => 'FutureProxy', 'ExecFuture' => 'PhutilExecutableFuture', 'ExecFutureTestCase' => 'PhutilTestCase', 'ExecPassthruTestCase' => 'PhutilTestCase', 'FileFinder' => 'Phobject', 'FileFinderTestCase' => 'PhutilTestCase', 'FileList' => 'Phobject', 'Filesystem' => 'Phobject', 'FilesystemException' => 'Exception', 'FilesystemTestCase' => 'PhutilTestCase', 'Future' => 'Phobject', 'FutureIterator' => array( 'Phobject', 'Iterator', ), 'FutureIteratorTestCase' => 'PhutilTestCase', 'FutureProxy' => 'Future', 'HTTPFuture' => 'BaseHTTPFuture', 'HTTPFutureCURLResponseStatus' => 'HTTPFutureResponseStatus', 'HTTPFutureCertificateResponseStatus' => 'HTTPFutureResponseStatus', 'HTTPFutureHTTPResponseStatus' => 'HTTPFutureResponseStatus', 'HTTPFutureParseResponseStatus' => 'HTTPFutureResponseStatus', 'HTTPFutureResponseStatus' => 'Exception', 'HTTPFutureTransportResponseStatus' => 'HTTPFutureResponseStatus', 'HTTPSFuture' => 'BaseHTTPFuture', 'ImmediateFuture' => 'Future', 'LibphutilUSEnglishTranslation' => 'PhutilTranslation', 'LinesOfALarge' => array( 'Phobject', 'Iterator', ), 'LinesOfALargeExecFuture' => 'LinesOfALarge', 'LinesOfALargeExecFutureTestCase' => 'PhutilTestCase', 'LinesOfALargeFile' => 'LinesOfALarge', 'LinesOfALargeFileTestCase' => 'PhutilTestCase', 'MFilterTestHelper' => 'Phobject', 'PHPASTParserTestCase' => 'PhutilTestCase', 'PhageAction' => 'Phobject', 'PhageAgentAction' => 'PhageAction', 'PhageAgentBootloader' => 'Phobject', 'PhageAgentTestCase' => 'PhutilTestCase', 'PhageExecuteAction' => 'PhageAction', 'PhageLocalAction' => 'PhageAgentAction', 'PhagePHPAgent' => 'Phobject', 'PhagePHPAgentBootloader' => 'PhageAgentBootloader', 'PhagePlanAction' => 'PhageAction', 'Phobject' => 'Iterator', 'PhobjectTestCase' => 'PhutilTestCase', 'PhutilAPCKeyValueCache' => 'PhutilKeyValueCache', 'PhutilAWSCloudFormationFuture' => 'PhutilAWSFuture', 'PhutilAWSCloudWatchFuture' => 'PhutilAWSFuture', 'PhutilAWSEC2Future' => 'PhutilAWSFuture', 'PhutilAWSException' => 'Exception', 'PhutilAWSFuture' => 'FutureProxy', 'PhutilAWSManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhutilAWSS3DeleteManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow', 'PhutilAWSS3Future' => 'PhutilAWSFuture', 'PhutilAWSS3GetManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow', 'PhutilAWSS3ManagementWorkflow' => 'PhutilAWSManagementWorkflow', 'PhutilAWSS3PutManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow', 'PhutilAWSv4Signature' => 'Phobject', 'PhutilAWSv4SignatureTestCase' => 'PhutilTestCase', 'PhutilAggregateException' => 'Exception', 'PhutilAllCapsEnglishLocale' => 'PhutilLocale', 'PhutilArgumentParser' => 'Phobject', 'PhutilArgumentParserException' => 'Exception', 'PhutilArgumentParserTestCase' => 'PhutilTestCase', 'PhutilArgumentSpecification' => 'Phobject', 'PhutilArgumentSpecificationException' => 'PhutilArgumentParserException', 'PhutilArgumentSpecificationTestCase' => 'PhutilTestCase', 'PhutilArgumentSpellingCorrector' => 'Phobject', 'PhutilArgumentSpellingCorrectorTestCase' => 'PhutilTestCase', 'PhutilArgumentUsageException' => 'PhutilArgumentParserException', 'PhutilArgumentWorkflow' => 'Phobject', 'PhutilArray' => array( 'Phobject', 'Countable', 'ArrayAccess', 'Iterator', ), 'PhutilArrayTestCase' => 'PhutilTestCase', 'PhutilArrayWithDefaultValue' => 'PhutilArray', 'PhutilAsanaFuture' => 'FutureProxy', 'PhutilBacktraceSignalHandler' => 'PhutilSignalHandler', 'PhutilBallOfPHP' => 'Phobject', 'PhutilBinaryAnalyzer' => 'Phobject', 'PhutilBinaryAnalyzerTestCase' => 'PhutilTestCase', 'PhutilBootloaderException' => 'Exception', 'PhutilBritishEnglishLocale' => 'PhutilLocale', 'PhutilBufferedIterator' => array( 'Phobject', 'Iterator', ), 'PhutilBufferedIteratorTestCase' => 'PhutilTestCase', 'PhutilBugtraqParser' => 'Phobject', 'PhutilBugtraqParserTestCase' => 'PhutilTestCase', 'PhutilCIDRBlock' => 'Phobject', 'PhutilCIDRList' => 'Phobject', 'PhutilCallbackFilterIterator' => 'FilterIterator', 'PhutilCallbackSignalHandler' => 'PhutilSignalHandler', 'PhutilChannel' => 'Phobject', 'PhutilChannelChannel' => 'PhutilChannel', 'PhutilChannelTestCase' => 'PhutilTestCase', 'PhutilChunkedIterator' => array( 'Phobject', 'Iterator', ), 'PhutilChunkedIteratorTestCase' => 'PhutilTestCase', 'PhutilClassMapQuery' => 'Phobject', 'PhutilCloudWatchMetric' => 'Phobject', 'PhutilCommandString' => 'Phobject', 'PhutilConsole' => 'Phobject', 'PhutilConsoleBlock' => 'PhutilConsoleView', 'PhutilConsoleError' => 'PhutilConsoleLogLine', 'PhutilConsoleFormatter' => 'Phobject', 'PhutilConsoleInfo' => 'PhutilConsoleLogLine', 'PhutilConsoleList' => 'PhutilConsoleView', 'PhutilConsoleLogLine' => 'PhutilConsoleView', 'PhutilConsoleMessage' => 'Phobject', 'PhutilConsoleMetrics' => 'Phobject', 'PhutilConsoleMetricsSignalHandler' => 'PhutilSignalHandler', 'PhutilConsoleProgressBar' => 'Phobject', 'PhutilConsoleProgressSink' => 'PhutilProgressSink', 'PhutilConsoleServer' => 'Phobject', 'PhutilConsoleServerChannel' => 'PhutilChannelChannel', 'PhutilConsoleSkip' => 'PhutilConsoleLogLine', 'PhutilConsoleStdinNotInteractiveException' => 'Exception', 'PhutilConsoleSyntaxHighlighter' => 'Phobject', 'PhutilConsoleTable' => 'PhutilConsoleView', 'PhutilConsoleView' => 'Phobject', 'PhutilConsoleWarning' => 'PhutilConsoleLogLine', 'PhutilConsoleWrapTestCase' => 'PhutilTestCase', 'PhutilContextFreeGrammar' => 'Phobject', 'PhutilCowsay' => 'Phobject', 'PhutilCowsayTestCase' => 'PhutilTestCase', 'PhutilCsprintfTestCase' => 'PhutilTestCase', 'PhutilCzechLocale' => 'PhutilLocale', 'PhutilDOMNode' => 'Phobject', 'PhutilDaemon' => 'Phobject', 'PhutilDaemonHandle' => 'Phobject', 'PhutilDaemonOverseer' => 'Phobject', 'PhutilDaemonOverseerModule' => 'Phobject', 'PhutilDaemonPool' => 'Phobject', 'PhutilDefaultSyntaxHighlighter' => 'Phobject', 'PhutilDefaultSyntaxHighlighterEngine' => 'PhutilSyntaxHighlighterEngine', 'PhutilDefaultSyntaxHighlighterEnginePygmentsFuture' => 'FutureProxy', 'PhutilDefaultSyntaxHighlighterEngineTestCase' => 'PhutilTestCase', 'PhutilDeferredLog' => 'Phobject', 'PhutilDeferredLogTestCase' => 'PhutilTestCase', 'PhutilDiffBinaryAnalyzer' => 'PhutilBinaryAnalyzer', 'PhutilDirectedScalarGraph' => 'AbstractDirectedGraph', 'PhutilDirectoryFixture' => 'Phobject', 'PhutilDirectoryKeyValueCache' => 'PhutilKeyValueCache', 'PhutilDivinerSyntaxHighlighter' => 'Phobject', 'PhutilDocblockParser' => 'Phobject', 'PhutilDocblockParserTestCase' => 'PhutilTestCase', 'PhutilEditDistanceMatrix' => 'Phobject', 'PhutilEditDistanceMatrixTestCase' => 'PhutilTestCase', 'PhutilEditorConfig' => 'Phobject', 'PhutilEditorConfigTestCase' => 'PhutilTestCase', 'PhutilEmailAddress' => 'Phobject', 'PhutilEmailAddressTestCase' => 'PhutilTestCase', 'PhutilEmojiLocale' => 'PhutilLocale', 'PhutilEnglishCanadaLocale' => 'PhutilLocale', 'PhutilErrorHandler' => 'Phobject', 'PhutilErrorHandlerTestCase' => 'PhutilTestCase', 'PhutilErrorTrap' => 'Phobject', 'PhutilEvent' => 'Phobject', 'PhutilEventConstants' => 'Phobject', 'PhutilEventEngine' => 'Phobject', 'PhutilEventListener' => 'Phobject', 'PhutilEventType' => 'PhutilEventConstants', 'PhutilExampleBufferedIterator' => 'PhutilBufferedIterator', 'PhutilExcessiveServiceCallsDaemon' => 'PhutilTortureTestDaemon', 'PhutilExecChannel' => 'PhutilChannel', 'PhutilExecPassthru' => 'PhutilExecutableFuture', 'PhutilExecutableFuture' => 'Future', 'PhutilExecutionEnvironment' => 'Phobject', 'PhutilExtensionsTestCase' => 'PhutilTestCase', 'PhutilFatalDaemon' => 'PhutilTortureTestDaemon', 'PhutilFileLock' => 'PhutilLock', 'PhutilFileLockTestCase' => 'PhutilTestCase', 'PhutilFileTree' => 'Phobject', 'PhutilFrenchLocale' => 'PhutilLocale', 'PhutilGermanLocale' => 'PhutilLocale', 'PhutilGitBinaryAnalyzer' => 'PhutilBinaryAnalyzer', 'PhutilGitHubFuture' => 'FutureProxy', 'PhutilGitHubResponse' => 'Phobject', 'PhutilGitURI' => 'Phobject', 'PhutilGitURITestCase' => 'PhutilTestCase', 'PhutilHTMLParser' => 'Phobject', 'PhutilHTMLParserTestCase' => 'PhutilTestCase', 'PhutilHTTPEngineExtension' => 'Phobject', 'PhutilHTTPResponse' => 'Phobject', 'PhutilHTTPResponseParser' => 'Phobject', 'PhutilHTTPResponseParserTestCase' => 'PhutilTestCase', 'PhutilHangForeverDaemon' => 'PhutilTortureTestDaemon', 'PhutilHashingIterator' => array( 'PhutilProxyIterator', 'Iterator', ), 'PhutilHashingIteratorTestCase' => 'PhutilTestCase', 'PhutilHelpArgumentWorkflow' => 'PhutilArgumentWorkflow', 'PhutilHgsprintfTestCase' => 'PhutilTestCase', 'PhutilHighIntensityIntervalDaemon' => 'PhutilTortureTestDaemon', 'PhutilINIParserException' => 'Exception', 'PhutilIPAddress' => 'Phobject', 'PhutilIPAddressTestCase' => 'PhutilTestCase', 'PhutilIPv4Address' => 'PhutilIPAddress', 'PhutilIPv6Address' => 'PhutilIPAddress', 'PhutilInRequestKeyValueCache' => 'PhutilKeyValueCache', 'PhutilInteractiveEditor' => 'Phobject', 'PhutilInvalidRuleParserGeneratorException' => 'PhutilParserGeneratorException', 'PhutilInvalidStateException' => 'Exception', 'PhutilInvalidStateExceptionTestCase' => 'PhutilTestCase', 'PhutilInvisibleSyntaxHighlighter' => 'Phobject', 'PhutilIrreducibleRuleParserGeneratorException' => 'PhutilParserGeneratorException', 'PhutilJSON' => 'Phobject', 'PhutilJSONFragmentLexer' => 'PhutilLexer', 'PhutilJSONFragmentLexerHighlighterTestCase' => 'PhutilTestCase', 'PhutilJSONParser' => 'Phobject', 'PhutilJSONParserException' => 'Exception', 'PhutilJSONParserTestCase' => 'PhutilTestCase', 'PhutilJSONProtocolChannel' => 'PhutilProtocolChannel', 'PhutilJSONProtocolChannelTestCase' => 'PhutilTestCase', 'PhutilJSONTestCase' => 'PhutilTestCase', 'PhutilJavaFragmentLexer' => 'PhutilLexer', 'PhutilKeyValueCache' => 'Phobject', 'PhutilKeyValueCacheNamespace' => 'PhutilKeyValueCacheProxy', 'PhutilKeyValueCacheProfiler' => 'PhutilKeyValueCacheProxy', 'PhutilKeyValueCacheProxy' => 'PhutilKeyValueCache', 'PhutilKeyValueCacheStack' => 'PhutilKeyValueCache', 'PhutilKeyValueCacheTestCase' => 'PhutilTestCase', 'PhutilKoreanLocale' => 'PhutilLocale', 'PhutilLanguageGuesser' => 'Phobject', 'PhutilLanguageGuesserTestCase' => 'PhutilTestCase', 'PhutilLexer' => 'Phobject', 'PhutilLexerSyntaxHighlighter' => 'PhutilSyntaxHighlighter', 'PhutilLibraryConflictException' => 'Exception', 'PhutilLibraryMapBuilder' => 'Phobject', 'PhutilLibraryTestCase' => 'PhutilTestCase', 'PhutilLocale' => 'Phobject', 'PhutilLocaleTestCase' => 'PhutilTestCase', 'PhutilLock' => 'Phobject', 'PhutilLockException' => 'Exception', 'PhutilLogFileChannel' => 'PhutilChannelChannel', 'PhutilLunarPhase' => 'Phobject', 'PhutilLunarPhaseTestCase' => 'PhutilTestCase', 'PhutilMarkupEngine' => 'Phobject', 'PhutilMarkupTestCase' => 'PhutilTestCase', 'PhutilMemcacheKeyValueCache' => 'PhutilKeyValueCache', 'PhutilMercurialBinaryAnalyzer' => 'PhutilBinaryAnalyzer', 'PhutilMethodNotImplementedException' => 'Exception', 'PhutilMetricsChannel' => 'PhutilChannelChannel', 'PhutilMissingSymbolException' => 'Exception', 'PhutilModuleUtilsTestCase' => 'PhutilTestCase', 'PhutilNiceDaemon' => 'PhutilTortureTestDaemon', 'PhutilNumber' => 'Phobject', 'PhutilOAuth1Future' => 'FutureProxy', 'PhutilOAuth1FutureTestCase' => 'PhutilTestCase', 'PhutilOnDiskKeyValueCache' => 'PhutilKeyValueCache', 'PhutilOpaqueEnvelope' => 'Phobject', 'PhutilOpaqueEnvelopeKey' => 'Phobject', 'PhutilOpaqueEnvelopeTestCase' => 'PhutilTestCase', 'PhutilPHPFragmentLexer' => 'PhutilLexer', 'PhutilPHPFragmentLexerHighlighterTestCase' => 'PhutilTestCase', 'PhutilPHPFragmentLexerTestCase' => 'PhutilTestCase', 'PhutilPHPObjectProtocolChannel' => 'PhutilProtocolChannel', 'PhutilPHPObjectProtocolChannelTestCase' => 'PhutilTestCase', 'PhutilParserGenerator' => 'Phobject', 'PhutilParserGeneratorException' => 'Exception', 'PhutilParserGeneratorTestCase' => 'PhutilTestCase', 'PhutilPayPalAPIFuture' => 'FutureProxy', 'PhutilPersonTest' => array( 'Phobject', 'PhutilPerson', ), 'PhutilPhtTestCase' => 'PhutilTestCase', 'PhutilPirateEnglishLocale' => 'PhutilLocale', 'PhutilPortugueseBrazilLocale' => 'PhutilLocale', 'PhutilPortuguesePortugalLocale' => 'PhutilLocale', 'PhutilPostmarkFuture' => 'FutureProxy', 'PhutilPregsprintfTestCase' => 'PhutilTestCase', 'PhutilProcessGroupDaemon' => 'PhutilTortureTestDaemon', 'PhutilProcessQuery' => 'Phobject', 'PhutilProcessRef' => 'Phobject', 'PhutilProcessRefTestCase' => 'PhutilTestCase', 'PhutilProgressSink' => 'Phobject', - 'PhutilProseDiff' => 'Phobject', - 'PhutilProseDiffTestCase' => 'PhutilTestCase', - 'PhutilProseDifferenceEngine' => 'Phobject', 'PhutilProtocolChannel' => 'PhutilChannelChannel', 'PhutilProxyException' => 'Exception', 'PhutilProxyIterator' => array( 'Phobject', 'Iterator', ), 'PhutilPygmentizeBinaryAnalyzer' => 'PhutilBinaryAnalyzer', 'PhutilPygmentizeParser' => 'Phobject', 'PhutilPygmentizeParserTestCase' => 'PhutilTestCase', 'PhutilPygmentsSyntaxHighlighter' => 'Phobject', 'PhutilPythonFragmentLexer' => 'PhutilLexer', 'PhutilQueryStringParser' => 'Phobject', 'PhutilQueryStringParserTestCase' => 'PhutilTestCase', 'PhutilRainbowSyntaxHighlighter' => 'Phobject', 'PhutilRawEnglishLocale' => 'PhutilLocale', 'PhutilReadableSerializer' => 'Phobject', 'PhutilReadableSerializerTestCase' => 'PhutilTestCase', 'PhutilRope' => 'Phobject', 'PhutilRopeTestCase' => 'PhutilTestCase', 'PhutilSafeHTML' => 'Phobject', 'PhutilSafeHTMLTestCase' => 'PhutilTestCase', 'PhutilSaturateStdoutDaemon' => 'PhutilTortureTestDaemon', 'PhutilSearchQueryCompiler' => 'Phobject', 'PhutilSearchQueryCompilerSyntaxException' => 'Exception', 'PhutilSearchQueryCompilerTestCase' => 'PhutilTestCase', 'PhutilSearchQueryToken' => 'Phobject', 'PhutilSearchStemmer' => 'Phobject', 'PhutilSearchStemmerTestCase' => 'PhutilTestCase', 'PhutilServiceProfiler' => 'Phobject', 'PhutilShellLexer' => 'PhutilLexer', 'PhutilShellLexerTestCase' => 'PhutilTestCase', 'PhutilSignalHandler' => 'Phobject', 'PhutilSignalRouter' => 'Phobject', 'PhutilSimpleOptions' => 'Phobject', 'PhutilSimpleOptionsLexer' => 'PhutilLexer', 'PhutilSimpleOptionsLexerTestCase' => 'PhutilTestCase', 'PhutilSimpleOptionsTestCase' => 'PhutilTestCase', 'PhutilSimplifiedChineseLocale' => 'PhutilLocale', 'PhutilSlackFuture' => 'FutureProxy', 'PhutilSocketChannel' => 'PhutilChannel', 'PhutilSortVector' => 'Phobject', 'PhutilSpanishSpainLocale' => 'PhutilLocale', 'PhutilSprite' => 'Phobject', 'PhutilSpriteSheet' => 'Phobject', 'PhutilStreamIterator' => array( 'Phobject', 'Iterator', ), 'PhutilSubversionBinaryAnalyzer' => 'PhutilBinaryAnalyzer', 'PhutilSyntaxHighlighter' => 'Phobject', 'PhutilSyntaxHighlighterEngine' => 'Phobject', 'PhutilSyntaxHighlighterException' => 'Exception', 'PhutilSystem' => 'Phobject', 'PhutilSystemTestCase' => 'PhutilTestCase', 'PhutilTerminalString' => 'Phobject', 'PhutilTestPhobject' => 'Phobject', 'PhutilTortureTestDaemon' => 'PhutilDaemon', 'PhutilTraditionalChineseLocale' => 'PhutilLocale', 'PhutilTranslation' => 'Phobject', 'PhutilTranslationTestCase' => 'PhutilTestCase', 'PhutilTranslator' => 'Phobject', 'PhutilTranslatorTestCase' => 'PhutilTestCase', 'PhutilTsprintfTestCase' => 'PhutilTestCase', 'PhutilTwitchFuture' => 'FutureProxy', 'PhutilTypeCheckException' => 'Exception', 'PhutilTypeExtraParametersException' => 'Exception', 'PhutilTypeLexer' => 'PhutilLexer', 'PhutilTypeMissingParametersException' => 'Exception', 'PhutilTypeSpec' => 'Phobject', 'PhutilTypeSpecTestCase' => 'PhutilTestCase', 'PhutilURI' => 'Phobject', 'PhutilURITestCase' => 'PhutilTestCase', 'PhutilUSEnglishLocale' => 'PhutilLocale', 'PhutilUTF8StringTruncator' => 'Phobject', 'PhutilUTF8TestCase' => 'PhutilTestCase', 'PhutilUnknownSymbolParserGeneratorException' => 'PhutilParserGeneratorException', 'PhutilUnreachableRuleParserGeneratorException' => 'PhutilParserGeneratorException', 'PhutilUnreachableTerminalParserGeneratorException' => 'PhutilParserGeneratorException', 'PhutilUrisprintfTestCase' => 'PhutilTestCase', 'PhutilUtilsTestCase' => 'PhutilTestCase', 'PhutilVeryWowEnglishLocale' => 'PhutilLocale', 'PhutilWordPressFuture' => 'FutureProxy', 'PhutilXHPASTBinary' => 'Phobject', 'PhutilXHPASTSyntaxHighlighter' => 'Phobject', 'PhutilXHPASTSyntaxHighlighterFuture' => 'FutureProxy', 'PhutilXHPASTSyntaxHighlighterTestCase' => 'PhutilTestCase', 'TempFile' => 'Phobject', 'TestAbstractDirectedGraph' => 'AbstractDirectedGraph', 'XHPASTNode' => 'AASTNode', 'XHPASTNodeTestCase' => 'PhutilTestCase', 'XHPASTSyntaxErrorException' => 'Exception', 'XHPASTToken' => 'AASTToken', 'XHPASTTree' => 'AASTTree', 'XHPASTTreeTestCase' => 'PhutilTestCase', 'XsprintfUnknownConversionException' => 'InvalidArgumentException', ), )); diff --git a/src/utils/PhutilProseDiff.php b/src/utils/PhutilProseDiff.php deleted file mode 100644 index df34d64..0000000 --- a/src/utils/PhutilProseDiff.php +++ /dev/null @@ -1,292 +0,0 @@ -parts[] = array( - 'type' => $type, - 'text' => $text, - ); - return $this; - } - - public function getParts() { - return $this->parts; - } - - /** - * Get diff parts, but replace large blocks of unchanged text with "." - * parts representing missing context. - */ - public function getSummaryParts() { - $parts = $this->getParts(); - - $head_key = head_key($parts); - $last_key = last_key($parts); - - $results = array(); - foreach ($parts as $key => $part) { - $is_head = ($key == $head_key); - $is_last = ($key == $last_key); - - switch ($part['type']) { - case '=': - $pieces = $this->splitTextForSummary($part['text']); - - if ($is_head || $is_last) { - $need = 2; - } else { - $need = 3; - } - - // We don't have enough pieces to omit anything, so just continue. - if (count($pieces) < $need) { - $results[] = $part; - break; - } - - if (!$is_head) { - $results[] = array( - 'type' => '=', - 'text' => head($pieces), - ); - } - - $results[] = array( - 'type' => '.', - 'text' => null, - ); - - if (!$is_last) { - $results[] = array( - 'type' => '=', - 'text' => last($pieces), - ); - } - break; - default: - $results[] = $part; - break; - } - } - - return $results; - } - - - public function reorderParts() { - // Reorder sequences of removed and added sections to put all the "-" - // parts together first, then all the "+" parts together. This produces - // a more human-readable result than intermingling them. - - $o_run = array(); - $n_run = array(); - $result = array(); - foreach ($this->parts as $part) { - $type = $part['type']; - switch ($type) { - case '-': - $o_run[] = $part; - break; - case '+': - $n_run[] = $part; - break; - default: - if ($o_run || $n_run) { - foreach ($this->combineRuns($o_run, $n_run) as $merged_part) { - $result[] = $merged_part; - } - $o_run = array(); - $n_run = array(); - } - $result[] = $part; - break; - } - } - - if ($o_run || $n_run) { - foreach ($this->combineRuns($o_run, $n_run) as $part) { - $result[] = $part; - } - } - - // Now, combine consecuitive runs of the same type of change (like a - // series of "-" parts) into a single run. - $combined = array(); - - $last = null; - $last_text = null; - foreach ($result as $part) { - $type = $part['type']; - - if ($last !== $type) { - if ($last !== null) { - $combined[] = array( - 'type' => $last, - 'text' => $last_text, - ); - } - $last_text = null; - $last = $type; - } - - $last_text .= $part['text']; - } - - if ($last_text !== null) { - $combined[] = array( - 'type' => $last, - 'text' => $last_text, - ); - } - - $this->parts = $combined; - - return $this; - } - - private function combineRuns($o_run, $n_run) { - $o_merge = $this->mergeParts($o_run); - $n_merge = $this->mergeParts($n_run); - - // When removed and added blocks share a prefix or suffix, we sometimes - // want to count it as unchanged (for example, if it is whitespace) but - // sometimes want to count it as changed (for example, if it is a word - // suffix like "ing"). Find common prefixes and suffixes of these layout - // characters and emit them as "=" (unchanged) blocks. - - $layout_characters = array( - ' ' => true, - "\n" => true, - '.' => true, - '!' => true, - ',' => true, - '?' => true, - ']' => true, - '[' => true, - '(' => true, - ')' => true, - '<' => true, - '>' => true, - ); - - $o_text = $o_merge['text']; - $n_text = $n_merge['text']; - $o_len = strlen($o_text); - $n_len = strlen($n_text); - $min_len = min($o_len, $n_len); - - $prefix_len = 0; - for ($pos = 0; $pos < $min_len; $pos++) { - $o = $o_text[$pos]; - $n = $n_text[$pos]; - if ($o !== $n) { - break; - } - if (empty($layout_characters[$o])) { - break; - } - $prefix_len++; - } - - $suffix_len = 0; - for ($pos = 0; $pos < ($min_len - $prefix_len); $pos++) { - $o = $o_text[$o_len - ($pos + 1)]; - $n = $n_text[$n_len - ($pos + 1)]; - if ($o !== $n) { - break; - } - if (empty($layout_characters[$o])) { - break; - } - $suffix_len++; - } - - $results = array(); - - if ($prefix_len) { - $results[] = array( - 'type' => '=', - 'text' => substr($o_text, 0, $prefix_len), - ); - } - - if ($prefix_len < $o_len) { - $results[] = array( - 'type' => '-', - 'text' => substr( - $o_text, - $prefix_len, - $o_len - $prefix_len - $suffix_len), - ); - } - - if ($prefix_len < $n_len) { - $results[] = array( - 'type' => '+', - 'text' => substr( - $n_text, - $prefix_len, - $n_len - $prefix_len - $suffix_len), - ); - } - - if ($suffix_len) { - $results[] = array( - 'type' => '=', - 'text' => substr($o_text, -$suffix_len), - ); - } - - return $results; - } - - private function mergeParts(array $parts) { - $text = ''; - $type = null; - foreach ($parts as $part) { - $part_type = $part['type']; - if ($type === null) { - $type = $part_type; - } - if ($type !== $part_type) { - throw new Exception(pht('Can not merge parts of dissimilar types!')); - } - $text .= $part['text']; - } - - return array( - 'type' => $type, - 'text' => $text, - ); - } - - private function splitTextForSummary($text) { - $matches = null; - - $ok = preg_match('/^(\n*[^\n]+)\n/', $text, $matches); - if (!$ok) { - return array($text); - } - - $head = $matches[1]; - $text = substr($text, strlen($head)); - - $ok = preg_match('/\n([^\n]+\n*)\z/', $text, $matches); - if (!$ok) { - return array($text); - } - - $last = $matches[1]; - $text = substr($text, 0, -strlen($last)); - - if (!strlen(trim($text))) { - return array($head, $last); - } else { - return array($head, $text, $last); - } - } - -} diff --git a/src/utils/PhutilProseDifferenceEngine.php b/src/utils/PhutilProseDifferenceEngine.php deleted file mode 100644 index 5deb8e6..0000000 --- a/src/utils/PhutilProseDifferenceEngine.php +++ /dev/null @@ -1,209 +0,0 @@ -buildDiff($u, $v, 0); - } - - private function buildDiff($u, $v, $level) { - $u_parts = $this->splitCorpus($u, $level); - $v_parts = $this->splitCorpus($v, $level); - - $matrix = id(new PhutilEditDistanceMatrix()) - ->setMaximumLength(128) - ->setSequences($u_parts, $v_parts) - ->setComputeString(true); - - // For word-level and character-level changes, smooth the output string - // to reduce the choppiness of the diff. - if ($level > 1) { - $matrix->setApplySmoothing(PhutilEditDistanceMatrix::SMOOTHING_FULL); - } - - $u_pos = 0; - $v_pos = 0; - - $edits = $matrix->getEditString(); - $edits_length = strlen($edits); - - $diff = new PhutilProseDiff(); - for ($ii = 0; $ii < $edits_length; $ii++) { - $c = $edits[$ii]; - if ($c == 's') { - $diff->addPart('=', $u_parts[$u_pos]); - $u_pos++; - $v_pos++; - } else if ($c == 'd') { - $diff->addPart('-', $u_parts[$u_pos]); - $u_pos++; - } else if ($c == 'i') { - $diff->addPart('+', $v_parts[$v_pos]); - $v_pos++; - } else if ($c == 'x') { - $diff->addPart('-', $u_parts[$u_pos]); - $diff->addPart('+', $v_parts[$v_pos]); - $u_pos++; - $v_pos++; - } else { - throw new Exception( - pht( - 'Unexpected character ("%s") in edit string.', - $c)); - } - } - - $diff->reorderParts(); - - // If we just built a character-level diff, we're all done and do not - // need to go any deeper. - if ($level == 3) { - return $diff; - } - - $blocks = array(); - $block = null; - foreach ($diff->getParts() as $part) { - $type = $part['type']; - $text = $part['text']; - switch ($type) { - case '=': - if ($block) { - $blocks[] = $block; - $block = null; - } - $blocks[] = array( - 'type' => $type, - 'text' => $text, - ); - break; - case '-': - if (!$block) { - $block = array( - 'type' => '!', - 'old' => '', - 'new' => '', - ); - } - $block['old'] .= $text; - break; - case '+': - if (!$block) { - $block = array( - 'type' => '!', - 'old' => '', - 'new' => '', - ); - } - $block['new'] .= $text; - break; - } - } - - if ($block) { - $blocks[] = $block; - } - - $result = new PhutilProseDiff(); - foreach ($blocks as $block) { - $type = $block['type']; - if ($type == '=') { - $result->addPart('=', $block['text']); - } else { - $old = $block['old']; - $new = $block['new']; - if (!strlen($old) && !strlen($new)) { - // Nothing to do. - } else if (!strlen($old)) { - $result->addPart('+', $new); - } else if (!strlen($new)) { - $result->addPart('-', $old); - } else { - if ($matrix->didReachMaximumLength()) { - // If this text was too big to diff, don't try to subdivide it. - $result->addPart('-', $old); - $result->addPart('+', $new); - } else { - $subdiff = $this->buildDiff( - $old, - $new, - $level + 1); - - foreach ($subdiff->getParts() as $part) { - $result->addPart($part['type'], $part['text']); - } - } - } - } - } - - $result->reorderParts(); - - return $result; - } - - private function splitCorpus($corpus, $level) { - switch ($level) { - case 0: - // Level 0: Split into paragraphs. - $expr = '/([\n]+)/'; - break; - case 1: - // Level 1: Split into sentences. - $expr = '/([\n,!;?\.]+)/'; - break; - case 2: - // Level 2: Split into words. - $expr = '/(\s+)/'; - break; - case 3: - // Level 3: Split into characters. - return phutil_utf8v_combined($corpus); - } - - $pieces = preg_split($expr, $corpus, -1, PREG_SPLIT_DELIM_CAPTURE); - return $this->stitchPieces($pieces, $level); - } - - private function stitchPieces(array $pieces, $level) { - $results = array(); - $count = count($pieces); - for ($ii = 0; $ii < $count; $ii += 2) { - $result = $pieces[$ii]; - if ($ii + 1 < $count) { - $result .= $pieces[$ii + 1]; - } - - if ($level < 2) { - // Split pieces into separate text and whitespace sections: make one - // piece out of all the whitespace at the beginning, one piece out of - // all the actual text in the middle, and one piece out of all the - // whitespace at the end. - - $matches = null; - preg_match('/^(\s*)(.*?)(\s*)\z/', $result, $matches); - - if (strlen($matches[1])) { - $results[] = $matches[1]; - } - if (strlen($matches[2])) { - $results[] = $matches[2]; - } - if (strlen($matches[3])) { - $results[] = $matches[3]; - } - } else { - $results[] = $result; - } - } - - // If the input ended with a delimiter, we can get an empty final piece. - // Just discard it. - if (last($results) == '') { - array_pop($results); - } - - return $results; - } - -} diff --git a/src/utils/__tests__/PhutilProseDiffTestCase.php b/src/utils/__tests__/PhutilProseDiffTestCase.php deleted file mode 100644 index bf0375e..0000000 --- a/src/utils/__tests__/PhutilProseDiffTestCase.php +++ /dev/null @@ -1,245 +0,0 @@ -assertProseParts( - '', - '', - array(), - pht('Empty')); - - $this->assertProseParts( - "xxx\nyyy", - "xxx\nzzz\nyyy", - array( - "= xxx\n", - "+ zzz\n", - '= yyy', - ), - pht('Add Paragraph')); - - $this->assertProseParts( - "xxx\nzzz\nyyy", - "xxx\nyyy", - array( - "= xxx\n", - "- zzz\n", - '= yyy', - ), - pht('Remove Paragraph')); - - - // Without smoothing, the alogorithm identifies that "shark" and "cat" - // both contain the letter "a" and tries to express this as a very - // fine-grained edit which replaces "sh" with "c" and then "rk" with "t". - // This is technically correct, but it is much easier for human viewers to - // parse if we smooth this into a single removal and a single addition. - - $this->assertProseParts( - 'They say the shark has nine lives.', - 'They say the cat has nine lives.', - array( - '= They say the ', - '- shark', - '+ cat', - '= has nine lives.', - ), - pht('"Shark/cat" word edit smoothenss.')); - - $this->assertProseParts( - 'Rising quickly, she says', - 'Rising quickly, she remarks:', - array( - '= Rising quickly, she ', - '- says', - '+ remarks:', - ), - pht('"Says/remarks" word edit smoothenss.')); - - $this->assertProseParts( - 'See screenshots', - 'Viewed video files', - array( - '- See screenshots', - '+ Viewed video files', - ), - pht('Complete paragraph rewrite.')); - - $this->assertProseParts( - 'xaaax', - 'xbbbx', - array( - '- xaaax', - '+ xbbbx', - ), - pht('Whole word rewrite with common prefix and suffix.')); - - $this->assertProseParts( - ' aaa ', - ' bbb ', - array( - '= ', - '- aaa', - '+ bbb', - '= ', - ), - pht('Whole word rewrite with whitespace prefix and suffix.')); - - $this->assertSummaryProseParts( - "a\nb\nc\nd\ne\nf\ng\nh\n", - "a\nb\nc\nd\nX\nf\ng\nh\n", - array( - '.', - "= d\n", - '- e', - '+ X', - "= \nf", - '.', - ), - pht('Summary diff with middle change.')); - - $this->assertSummaryProseParts( - "a\nb\nc\nd\ne\nf\ng\nh\n", - "X\nb\nc\nd\ne\nf\ng\nh\n", - array( - '- a', - '+ X', - "= \nb", - '.', - ), - pht('Summary diff with head change.')); - - $this->assertSummaryProseParts( - "a\nb\nc\nd\ne\nf\ng\nh\n", - "a\nb\nc\nd\ne\nf\ng\nX\n", - array( - '.', - "= g\n", - '- h', - '+ X', - "= \n", - ), - pht('Summary diff with last change.')); - - $this->assertProseParts( - 'aaa aaa aaa aaa, bbb bbb bbb bbb.', - "aaa aaa aaa aaa, bbb bbb bbb bbb.\n\n- ccc ccc ccc", - array( - '= aaa aaa aaa aaa, bbb bbb bbb bbb.', - "+ \n\n- ccc ccc ccc", - ), - pht('Diff with new trailing content.')); - - $this->assertProseParts( - 'aaa aaa aaa aaa, bbb bbb bbb bbb.', - 'aaa aaa aaa aaa bbb bbb bbb bbb.', - array( - '= aaa aaa aaa aaa', - '- ,', - '= bbb bbb bbb bbb.', - ), - pht('Diff with a removed comma.')); - - $this->assertProseParts( - 'aaa aaa aaa aaa, bbb bbb bbb bbb.', - "aaa aaa aaa aaa bbb bbb bbb bbb.\n\n- ccc ccc ccc!", - array( - '= aaa aaa aaa aaa', - '- ,', - '= bbb bbb bbb bbb.', - "+ \n\n- ccc ccc ccc!", - ), - pht('Diff with a removed comma and new trailing content.')); - - $this->assertProseParts( - '[ ] Walnuts', - '[X] Walnuts', - array( - '= [', - '- ', - '+ X', - '= ] Walnuts', - ), - pht('Diff adding a tickmark to a checkbox list.')); - - $this->assertProseParts( - '[[ ./week49 ]]', - '[[ ./week50 ]]', - array( - '= [[ ./week', - '- 49', - '+ 50', - '= ]]', - ), - pht('Diff changing a remarkup wiki link target.')); - - // Create a large corpus with many sentences and paragraphs. - $large_paragraph = 'xyz. '; - $large_paragraph = str_repeat($large_paragraph, 50); - $large_paragraph = rtrim($large_paragraph); - - $large_corpus = $large_paragraph."\n\n"; - $large_corpus = str_repeat($large_corpus, 50); - $large_corpus = rtrim($large_corpus); - - $this->assertProseParts( - $large_corpus, - "aaa\n\n".$large_corpus."\n\nzzz", - array( - "+ aaa\n\n", - '= '.$large_corpus, - "+ \n\nzzz", - ), - pht('Adding initial and final lines to a large corpus.')); - - } - - private function assertProseParts($old, $new, array $expect_parts, $label) { - $engine = new PhutilProseDifferenceEngine(); - $diff = $engine->getDiff($old, $new); - - $parts = $diff->getParts(); - - $this->assertParts($expect_parts, $parts, $label); - } - - private function assertSummaryProseParts( - $old, - $new, - array $expect_parts, - $label) { - - $engine = new PhutilProseDifferenceEngine(); - $diff = $engine->getDiff($old, $new); - - $parts = $diff->getSummaryParts(); - - $this->assertParts($expect_parts, $parts, $label); - } - - private function assertParts( - array $expect, - array $actual_parts, - $label) { - - $actual = array(); - foreach ($actual_parts as $actual_part) { - $type = $actual_part['type']; - $text = $actual_part['text']; - - switch ($type) { - case '.': - $actual[] = $type; - break; - default: - $actual[] = "{$type} {$text}"; - break; - } - } - - $this->assertEqual($expect, $actual, $label); - } - - -}