mirror of
https://github.com/Facepunch/sbox-public.git
synced 2025-12-23 22:48:07 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
289 lines
7.6 KiB
C#
289 lines
7.6 KiB
C#
using Sandbox.Internal;
|
|
using System;
|
|
|
|
namespace Editor;
|
|
|
|
/// <summary>
|
|
/// Interface for editors to open code files.
|
|
/// Any class that implements this interface is automatically added to the list.
|
|
/// An editor is only enabled if <see cref="IsInstalled"/> returns true.
|
|
///
|
|
/// Decorate your implementation with a <see cref="TitleAttribute"/>.
|
|
/// </summary>
|
|
public interface ICodeEditor
|
|
{
|
|
/// <summary>
|
|
/// Opens a file in the editor, optionally at a line and column.
|
|
/// </summary>
|
|
public void OpenFile( string path, int? line = null, int? column = null );
|
|
|
|
/// <summary>
|
|
/// Open the solution of all sandbox projects
|
|
/// </summary>
|
|
public void OpenSolution();
|
|
|
|
/// <summary>
|
|
/// Open given addon in the editor.
|
|
/// </summary>
|
|
public void OpenAddon( Project addon );
|
|
|
|
/// <summary>
|
|
/// Whether or not this editor is installed.
|
|
/// </summary>
|
|
public bool IsInstalled();
|
|
}
|
|
|
|
/// <summary>
|
|
/// For opening source code files in whatever code editor the user has selected.
|
|
/// </summary>
|
|
public static partial class CodeEditor
|
|
{
|
|
private static ICodeEditor _current;
|
|
/// <summary>
|
|
/// The current code editor we're using.
|
|
/// </summary>
|
|
[Title( "Code Editor" )]
|
|
public static ICodeEditor Current
|
|
{
|
|
get
|
|
{
|
|
if ( _current == null )
|
|
{
|
|
var editorName = EditorCookie.GetString( "CodeEditor", GetDefault() );
|
|
var editorType = EditorTypeLibrary.GetTypes<ICodeEditor>().FirstOrDefault( t => t.Name == editorName );
|
|
|
|
// Check if our selected editor is still valid
|
|
if ( editorType != null )
|
|
{
|
|
var editor = editorType.Create<ICodeEditor>();
|
|
if ( !editor.IsInstalled() )
|
|
{
|
|
Log.Warning( $"Code editor '{editorName}' not installed, using default" );
|
|
editorType = EditorTypeLibrary.GetTypes<ICodeEditor>().FirstOrDefault( t => t.Name == GetDefault() );
|
|
}
|
|
}
|
|
|
|
// Check if our selected editor even exists as a type
|
|
if ( editorType == null )
|
|
{
|
|
Log.Warning( $"Code editor '{editorName}' not found, using default" );
|
|
editorType = EditorTypeLibrary.GetTypes<ICodeEditor>().FirstOrDefault( t => t.Name == GetDefault() );
|
|
}
|
|
|
|
// If you seriously have no code editor installed, _current can just be null
|
|
if ( editorType != null )
|
|
{
|
|
EditorCookie.SetString( "CodeEditor", editorType.Name ); // Make sure the cookie gets reset if we're falling back
|
|
_current = editorType.Create<ICodeEditor>();
|
|
}
|
|
}
|
|
return _current;
|
|
}
|
|
set
|
|
{
|
|
_current = value;
|
|
EditorCookie.SetString( "CodeEditor", value.GetType().Name );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to find an editor type with a matching name, and checks to see if it's installed on our system.
|
|
/// </summary>
|
|
/// <param name="editorName"></param>
|
|
/// <returns></returns>
|
|
private static TypeDescription GetEditorDescription( string editorName )
|
|
{
|
|
return EditorTypeLibrary.GetTypes<ICodeEditor>().Where( x => !x.IsInterface && x.Name == editorName && x.Create<ICodeEditor>().IsInstalled() ).FirstOrDefault();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decides on a default code editor to use, defaults to Visual Studio or Visual Studio Code if not installed.
|
|
/// Since code editors are made in addon space, we don't have their types ready to use.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private static string GetDefault()
|
|
{
|
|
// Default to Visual Studio
|
|
var editorType = GetEditorDescription( "VisualStudio" );
|
|
if ( editorType != null ) return editorType.Name;
|
|
|
|
// Default to Visual Studio Code
|
|
editorType = GetEditorDescription( "VisualStudioCode" );
|
|
if ( editorType != null ) return editorType.Name;
|
|
|
|
// Find any available code editor..
|
|
return EditorTypeLibrary.GetTypes<ICodeEditor>()
|
|
.Where( x => !x.IsInterface && x.Create<ICodeEditor>().IsInstalled() )
|
|
.FirstOrDefault()
|
|
?.Name ?? null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Friendly name for our current code editor.
|
|
/// </summary>
|
|
public static string Title
|
|
{
|
|
get
|
|
{
|
|
if ( CodeEditor.Current != null )
|
|
{
|
|
var displayInfo = DisplayInfo.ForType( CodeEditor.Current.GetType(), true );
|
|
if ( !string.IsNullOrEmpty( displayInfo.Name ) )
|
|
return displayInfo.Name;
|
|
}
|
|
|
|
return "Code Editor";
|
|
}
|
|
}
|
|
|
|
private static void OpenFile( string path, int? line, int? column, string memberName )
|
|
{
|
|
ArgumentNullException.ThrowIfNullOrEmpty( path );
|
|
|
|
if ( AssetSystem.FindByPath( path ) is { } asset )
|
|
{
|
|
if ( !IAssetEditor.OpenInEditor( asset, out var editor ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( memberName is null || editor is null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
editor.SelectMember( memberName );
|
|
return;
|
|
}
|
|
|
|
if ( !System.IO.Path.IsPathRooted( path ) )
|
|
{
|
|
foreach ( var project in EditorUtility.Projects.GetAll() )
|
|
{
|
|
if ( !project.Active ) continue;
|
|
if ( !project.HasCompiler ) continue;
|
|
|
|
var codePath = project.GetCodePath();
|
|
var fullPath = System.IO.Path.Combine( codePath, path );
|
|
|
|
if ( System.IO.File.Exists( fullPath ) )
|
|
{
|
|
path = fullPath;
|
|
goto found;
|
|
}
|
|
}
|
|
|
|
Log.Error( $"Couldn't resolve relative path: '{path}'" );
|
|
return;
|
|
}
|
|
|
|
found:
|
|
|
|
if ( AssertCodeEditor() )
|
|
Current?.OpenFile( path, line, column );
|
|
}
|
|
|
|
public static void OpenFile( ISourcePathProvider location )
|
|
{
|
|
OpenFile(
|
|
location.Path,
|
|
(location as ISourceLineProvider)?.Line,
|
|
(location as ISourceColumnProvider)?.Column,
|
|
(location as IMemberNameProvider)?.MemberName );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens a file in the current editor, optionally at a line and column.
|
|
/// </summary>
|
|
public static void OpenFile( string path, int? line = null, int? column = null )
|
|
{
|
|
OpenFile( path, line, column, null );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the file exists and can be opened by the current code editor.
|
|
/// </summary>
|
|
/// <param name="path"></param>
|
|
/// <returns></returns>
|
|
public static bool CanOpenFile( string path )
|
|
{
|
|
if ( string.IsNullOrWhiteSpace( path ) ) return false;
|
|
|
|
if ( AssetSystem.FindByPath( path ) is { } asset )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( !System.IO.Path.IsPathRooted( path ) )
|
|
{
|
|
foreach ( var project in EditorUtility.Projects.GetAll() )
|
|
{
|
|
if ( !project.Active ) continue;
|
|
if ( !project.HasCompiler ) continue;
|
|
var codePath = project.GetCodePath();
|
|
var fullPath = System.IO.Path.Combine( codePath, path );
|
|
if ( System.IO.File.Exists( fullPath ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open the solution of all s&box projects
|
|
/// </summary>
|
|
public static void OpenSolution()
|
|
{
|
|
if ( AssertCodeEditor() )
|
|
Current?.OpenSolution();
|
|
}
|
|
|
|
public static void OpenAddon( Project addon )
|
|
{
|
|
if ( AssertCodeEditor() )
|
|
Current.OpenAddon( addon );
|
|
}
|
|
|
|
private static bool AssertCodeEditor()
|
|
{
|
|
if ( Current == null )
|
|
{
|
|
EditorUtility.DisplayDialog( "No Code Editor", "No code editor found, you'll want something like Visual Studio." );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds a .sln this path belongs to, this is pretty much entirely for internal usage to open engine slns
|
|
/// </summary>
|
|
public static string FindSolutionFromPath( string path )
|
|
{
|
|
if ( path == null || path.Length < 5 )
|
|
throw new Exception( $"Couldn't find solution file from path \"{path}\"" );
|
|
|
|
var addonFile = System.IO.Path.Combine( path, ".sbproj" );
|
|
if ( System.IO.File.Exists( addonFile ) )
|
|
{
|
|
return AddonSolutionPath();
|
|
}
|
|
|
|
var solutions = System.IO.Directory.EnumerateFiles( path, "*.slnx" ).ToArray();
|
|
if ( solutions.Length > 0 )
|
|
{
|
|
return string.Join( ";", solutions );
|
|
}
|
|
|
|
return FindSolutionFromPath( System.IO.Directory.GetParent( path ).FullName );
|
|
}
|
|
|
|
public static string AddonSolutionPath()
|
|
{
|
|
return $"{Project.Current.GetRootPath()}/{Project.Current.Config.Ident}.slnx";
|
|
}
|
|
}
|