#summary Source code access is now done via plugins

#ttp 330039 	EDITOR: Platform-agnostic editor code depends on Windows-only VSAccessor headers
#detail 	Source code access is now extensible via plugins, so any new editors can be easily added.
#add 	Added SourceCodeAccess module that routes access via plugins.
#change 	Moved much of the old VSAccessor code into a new VisualStudioSourceCodeAccess plugin.
#add 	Added a counterpart XCode plugin & migrated the code from FSourceCodeNavigation (Applescript etc.) into there.
#remove 	Removed applescript for XCode access (it is now done via code).
#remove 	Removed source code access functionality from platform layer.
#add 	Added details customization for source code access settings, so users can choose their own accessor.
#remove 	Removed dependencies on VSAccessor.
#change 	Changed API in SWidget to not require building a string to be parsed, instead this acesses and forwards filenames & line numbers.
#extra 	Tested on Mac by Mark S.
reviewed by 	Andrew.Brown

[CL 2048697 by Thomas Sarkanen in Main branch]
This commit is contained in:
Thomas Sarkanen
2014-04-23 19:19:51 -04:00
committed by UnrealBot
parent 23173e178d
commit 2e3d1f5aae
60 changed files with 1283 additions and 560 deletions

View File

@@ -0,0 +1,19 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "XCodeSourceCodeAccessPrivatePCH.h"
#include "Runtime/Core/Public/Features/IModularFeatures.h"
#include "XCodeSourceCodeAccessModule.h"
IMPLEMENT_MODULE( FXCodeSourceCodeAccessModule, XCodeSourceCodeAccess );
void FXCodeSourceCodeAccessModule::StartupModule()
{
// Bind our source control provider to the editor
IModularFeatures::Get().RegisterModularFeature(TEXT("SourceCodeAccessor"), &XCodeSourceCodeAccessor );
}
void FXCodeSourceCodeAccessModule::ShutdownModule()
{
// unbind provider from editor
IModularFeatures::Get().UnregisterModularFeature(TEXT("SourceCodeAccessor"), &XCodeSourceCodeAccessor);
}

View File

@@ -0,0 +1,16 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "XCodeSourceCodeAccessor.h"
class FXCodeSourceCodeAccessModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() OVERRIDE;
virtual void ShutdownModule() OVERRIDE;
private:
FXCodeSourceCodeAccessor XCodeSourceCodeAccessor;
};

View File

@@ -0,0 +1,7 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Core.h"
#include "ModuleManager.h"
#include "ISourceCodeAccessModule.h"

View File

@@ -0,0 +1,184 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "XCodeSourceCodeAccessPrivatePCH.h"
#include "XCodeSourceCodeAccessor.h"
#define LOCTEXT_NAMESPACE "XCodeSourceCodeAccessor"
/** Applescript we use to open XCode */
static const char* OpenXCodeAtFileAndLineAppleScript =
" on OpenXcodeAtFileAndLine(filepath, linenumber)\n"
" set theOffset to offset of \"/\" in filepath\n"
" tell application \"Xcode\"\n"
" activate\n"
" if theOffset is 1 then\n"
" open filepath\n"
" end if\n"
" tell application \"System Events\"\n"
" tell process \"Xcode\"\n"
" if theOffset is not 1 then\n"
" keystroke \"o\" using {command down, shift down}\n"
" repeat until window \"Open Quickly\" exists\n"
" end repeat\n"
" click text field 1 of window \"Open Quickly\"\n"
" set value of text field 1 of window \"Open Quickly\" to filepath\n"
" keystroke return\n"
" end if\n"
" keystroke \"l\" using command down\n"
" repeat until window \"Open Quickly\" exists\n"
" end repeat\n"
" click text field 1 of window \"Open Quickly\"\n"
" set value of text field 1 of window \"Open Quickly\" to linenumber\n"
" keystroke return\n"
" keystroke return\n"
" end tell\n"
" end tell\n"
" end tell\n"
" end OpenXcodeAtFileAndLine\n"
;
bool FXCodeSourceCodeAccessor::CanAccessSourceCode() const
{
return IFileManager::Get().DirectoryExists(TEXT("/Applications/Xcode.app"));
}
FName FXCodeSourceCodeAccessor::GetFName() const
{
return FName("XCodeSourceCodeAccessor");
}
FText FXCodeSourceCodeAccessor::GetNameText() const
{
return LOCTEXT("XCodeDisplayName", "Visual Studio");
}
FText FXCodeSourceCodeAccessor::GetDescriptionText() const
{
return LOCTEXT("XCodeDisplayDesc", "Open source code files in XCode");
}
bool FXCodeSourceCodeAccessor::OpenSolution()
{
const FString FullPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead( *FModuleManager::Get().GetSolutionFilepath() );
if ( FPaths::FileExists( FullPath ) )
{
FPlatformProcess::LaunchFileInDefaultExternalApplication( *FullPath );
return true;
}
return false;
}
bool FXCodeSourceCodeAccessor::OpenFileAtLine(const FString& FullPath, int32 LineNumber, int32 ColumnNumber)
{
ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>(TEXT("SourceCodeAccess"));
// column & line numbers are 1-based, so dont allow zero
if(LineNumber == 0)
{
LineNumber++;
}
if(ColumnNumber == 0)
{
ColumnNumber++;
}
if (!FPaths::FileExists(FullPath))
{
SourceCodeAccessModule.OnOpenFileFailed().Broadcast(FullPath);
return false;
}
if ( FModuleManager::Get().IsSolutionFilePresent() )
{
FString ProjPath = FPaths::ConvertRelativePathToFull(FModuleManager::Get().GetSolutionFilepath());
CFStringRef ProjPathString = FPlatformString::TCHARToCFString(*ProjPath);
NSString* ProjectPath = [(NSString*)ProjPathString stringByDeletingLastPathComponent];
[[NSWorkspace sharedWorkspace] openFile:ProjectPath withApplication:@"Xcode" andDeactivate:YES];
}
bool ExecutionSucceeded = false;
NSAppleScript* AppleScript = nil;
NSString* AppleScriptString = [NSString stringWithCString:OpenXCodeAtFileAndLineAppleScript encoding:NSUTF8StringEncoding];
AppleScript = [[NSAppleScript alloc] initWithSource:AppleScriptString];
int PID = [[NSProcessInfo processInfo] processIdentifier];
NSAppleEventDescriptor* ThisApplication = [NSAppleEventDescriptor descriptorWithDescriptorType:typeKernelProcessID bytes:&PID length:sizeof(PID)];
NSAppleEventDescriptor* ContainerEvent = [NSAppleEventDescriptor appleEventWithEventClass:'ascr' eventID:'psbr' targetDescriptor:ThisApplication returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
[ContainerEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:@"OpenXcodeAtFileAndLine"] forKeyword:'snam'];
{
NSAppleEventDescriptor* Arguments = [[NSAppleEventDescriptor alloc] initListDescriptor];
CFStringRef FileString = FPlatformString::TCHARToCFString(*FullPath);
NSString* Path = (NSString*)FileString;
if([Path isAbsolutePath] == NO)
{
NSString* CurDir = [[NSFileManager defaultManager] currentDirectoryPath];
NSString* ResolvedPath = [[NSString stringWithFormat:@"%@/%@", CurDir, Path] stringByResolvingSymlinksInPath];
if([[NSFileManager defaultManager] fileExistsAtPath:ResolvedPath])
{
Path = ResolvedPath;
}
else // If it doesn't exist, supply only the filename, we'll use Open Quickly to try and find it from Xcode
{
Path = [Path lastPathComponent];
}
}
[Arguments insertDescriptor:[NSAppleEventDescriptor descriptorWithString:Path] atIndex:([Arguments numberOfItems] + 1)];
CFRelease(FileString);
CFStringRef LineString = FPlatformString::TCHARToCFString(*FString::FromInt(LineNumber));
if(LineString)
{
[Arguments insertDescriptor:[NSAppleEventDescriptor descriptorWithString:(NSString*)LineString] atIndex:([Arguments numberOfItems] + 1)];
CFRelease(LineString);
}
else
{
[Arguments insertDescriptor:[NSAppleEventDescriptor descriptorWithString:@"1"] atIndex:([Arguments numberOfItems] + 1)];
}
[ContainerEvent setParamDescriptor:Arguments forKeyword:keyDirectObject];
[Arguments release];
}
NSDictionary* ExecutionError = nil;
[AppleScript executeAppleEvent:ContainerEvent error:&ExecutionError];
if(ExecutionError == nil)
{
ExecutionSucceeded = true;
}
[AppleScript release];
// Fallback to trivial implementation when something goes wrong (like not having permission for UI scripting)
if(ExecutionSucceeded == false)
{
FPlatformProcess::LaunchFileInDefaultExternalApplication(*FullPath);
}
return true;
}
bool FXCodeSourceCodeAccessor::OpenSourceFiles(const TArray<FString>& AbsoluteSourcePaths)
{
for ( const FString& SourcePath : AbsoluteSourcePaths )
{
FPlatformProcess::LaunchFileInDefaultExternalApplication(*SourcePath);
}
return true;
}
bool FXCodeSourceCodeAccessor::SaveAllOpenDocuments() const
{
return false;
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,19 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ISourceCodeAccessor.h"
class FXCodeSourceCodeAccessor : public ISourceCodeAccessor
{
public:
/** ISourceCodeAccessor implementation */
virtual bool CanAccessSourceCode() const OVERRIDE;
virtual FName GetFName() const OVERRIDE;
virtual FText GetNameText() const OVERRIDE;
virtual FText GetDescriptionText() const OVERRIDE;
virtual bool OpenSolution() OVERRIDE;
virtual bool OpenFileAtLine(const FString& FullPath, int32 LineNumber, int32 ColumnNumber = 0) OVERRIDE;
virtual bool OpenSourceFiles(const TArray<FString>& AbsoluteSourcePaths) OVERRIDE;
virtual bool SaveAllOpenDocuments() const OVERRIDE;
};

View File

@@ -0,0 +1,18 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
namespace UnrealBuildTool.Rules
{
public class XCodeSourceCodeAccess : ModuleRules
{
public XCodeSourceCodeAccess(TargetInfo Target)
{
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Core",
"SourceCodeAccess"
}
);
}
}
}