go to usage/declaration
This commit is contained in:
@@ -10,12 +10,14 @@ using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CodeRefactorings;
|
||||
using Microsoft.CodeAnalysis.Completion;
|
||||
using Microsoft.CodeAnalysis.FindSymbols;
|
||||
using Microsoft.CodeAnalysis.Host.Mef;
|
||||
using Microsoft.CodeAnalysis.MSBuild;
|
||||
using Microsoft.CodeAnalysis.Razor.Remote;
|
||||
using Microsoft.CodeAnalysis.Razor.SemanticTokens;
|
||||
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens;
|
||||
using Microsoft.CodeAnalysis.Shared.Extensions;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Roslyn.LanguageServer.Protocol;
|
||||
@@ -586,7 +588,7 @@ public class RoslynAnalysis(ILogger<RoslynAnalysis> logger, BuildService buildSe
|
||||
public async Task<(string updatedText, SharpIdeFileLinePosition sharpIdeFileLinePosition)> GetCompletionApplyChanges(SharpIdeFile file, CompletionItem completionItem, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var documentId = _workspace!.CurrentSolution.GetDocumentIdsWithFilePath(file.Path).Single();
|
||||
var document = _workspace.CurrentSolution.GetRequiredDocument(documentId);
|
||||
var document = SolutionExtensions.GetRequiredDocument(_workspace.CurrentSolution, documentId);
|
||||
var completionService = CompletionService.GetService(document) ?? throw new InvalidOperationException("Completion service is not available for the document.");
|
||||
|
||||
var completionChange = await completionService.GetChangeAsync(document, completionItem, commitCharacter: '.', cancellationToken: cancellationToken);
|
||||
@@ -661,6 +663,36 @@ public class RoslynAnalysis(ILogger<RoslynAnalysis> logger, BuildService buildSe
|
||||
return changedFilesWithText;
|
||||
}
|
||||
|
||||
public async Task<ISymbol?> GetEnclosingSymbolForReferenceLocation(ReferenceLocation referenceLocation)
|
||||
{
|
||||
var semanticModel = await referenceLocation.Document.GetSemanticModelAsync();
|
||||
if (semanticModel is null) return null;
|
||||
var enclosingSymbol = ReferenceLocationExtensions.GetEnclosingMethodOrPropertyOrField(semanticModel, referenceLocation);
|
||||
return enclosingSymbol;
|
||||
}
|
||||
|
||||
public async Task<ImmutableArray<ReferencedSymbol>> FindAllSymbolReferences(ISymbol symbol, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(FindAllSymbolReferences)}");
|
||||
await _solutionLoadedTcs.Task;
|
||||
|
||||
var solution = _workspace!.CurrentSolution;
|
||||
var references = await SymbolFinder.FindReferencesAsync(symbol, solution, cancellationToken);
|
||||
return references.AsImmutable();
|
||||
}
|
||||
|
||||
public async Task<(ISymbol?, LinePositionSpan?, TokenSemanticInfo?)> LookupSymbolSemanticInfo(SharpIdeFile fileModel, LinePosition linePosition)
|
||||
{
|
||||
await _solutionLoadedTcs.Task;
|
||||
var (symbol, linePositionSpan, semanticInfo) = fileModel switch
|
||||
{
|
||||
{ IsRazorFile: true } => await LookupSymbolSemanticInfoInRazor(fileModel, linePosition),
|
||||
{ IsCsharpFile: true } => await LookupSymbolSemanticInfoInCs(fileModel, linePosition),
|
||||
_ => (null, null, null)
|
||||
};
|
||||
return (symbol, linePositionSpan, semanticInfo);
|
||||
}
|
||||
|
||||
public async Task<(ISymbol?, LinePositionSpan?)> LookupSymbol(SharpIdeFile fileModel, LinePosition linePosition)
|
||||
{
|
||||
await _solutionLoadedTcs.Task;
|
||||
@@ -709,6 +741,46 @@ public class RoslynAnalysis(ILogger<RoslynAnalysis> logger, BuildService buildSe
|
||||
return GetSymbolAtPosition(semanticModel, syntaxRoot!, position);
|
||||
}
|
||||
|
||||
private async Task<(ISymbol? symbol, LinePositionSpan? linePositionSpan, TokenSemanticInfo? semanticInfo)> LookupSymbolSemanticInfoInCs(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath);
|
||||
var document = project.Documents.Single(s => s.FilePath == fileModel.Path);
|
||||
Guard.Against.Null(document, nameof(document));
|
||||
var sourceText = await document.GetTextAsync();
|
||||
var position = sourceText.GetPosition(linePosition);
|
||||
var semanticModel = await document.GetSemanticModelAsync();
|
||||
Guard.Against.Null(semanticModel, nameof(semanticModel));
|
||||
var syntaxRoot = await document.GetSyntaxRootAsync();
|
||||
var semanticInfo = await SymbolFinder.GetSemanticInfoAtPositionAsync(semanticModel, position, document.Project.Solution.Services, cancellationToken).ConfigureAwait(false);
|
||||
var (symbol, linePositionSpan) = GetSymbolAtPosition(semanticModel, syntaxRoot!, position);
|
||||
return (symbol, linePositionSpan, semanticInfo);
|
||||
}
|
||||
|
||||
private async Task<(ISymbol? symbol, LinePositionSpan? linePositionSpan, TokenSemanticInfo? semanticInfo)> LookupSymbolSemanticInfoInRazor(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sharpIdeProjectModel = ((IChildSharpIdeNode) fileModel).GetNearestProjectNode()!;
|
||||
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == sharpIdeProjectModel!.FilePath);
|
||||
|
||||
var additionalDocument = project.AdditionalDocuments.Single(s => s.FilePath == fileModel.Path);
|
||||
|
||||
var razorProjectSnapshot = _snapshotManager!.GetSnapshot(project);
|
||||
var documentSnapshot = razorProjectSnapshot.GetDocument(additionalDocument);
|
||||
|
||||
var razorCodeDocument = await razorProjectSnapshot.GetRequiredCodeDocumentAsync(documentSnapshot, cancellationToken);
|
||||
var razorCSharpDocument = razorCodeDocument.GetRequiredCSharpDocument();
|
||||
var generatedDocument = await razorProjectSnapshot.GetRequiredGeneratedDocumentAsync(documentSnapshot, cancellationToken);
|
||||
var generatedDocSyntaxRoot = await generatedDocument.GetSyntaxRootAsync(cancellationToken);
|
||||
|
||||
var razorText = await additionalDocument.GetTextAsync(cancellationToken);
|
||||
|
||||
var mappedPosition = MapRazorLinePositionToGeneratedCSharpAbsolutePosition(razorCSharpDocument, razorText, linePosition);
|
||||
var semanticModel = await generatedDocument.GetSemanticModelAsync(cancellationToken);
|
||||
var (symbol, linePositionSpan) = GetSymbolAtPosition(semanticModel!, generatedDocSyntaxRoot!, mappedPosition!.Value);
|
||||
|
||||
var semanticInfo = await SymbolFinder.GetSemanticInfoAtPositionAsync(semanticModel!, mappedPosition.Value, generatedDocument.Project.Solution.Services, cancellationToken).ConfigureAwait(false);
|
||||
return (symbol, linePositionSpan, semanticInfo);
|
||||
}
|
||||
|
||||
private (ISymbol? symbol, LinePositionSpan? linePositionSpan) GetSymbolAtPosition(SemanticModel semanticModel, SyntaxNode root, int position)
|
||||
{
|
||||
var node = root.FindToken(position).Parent!;
|
||||
|
||||
@@ -3,6 +3,8 @@ using Godot;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.Completion;
|
||||
using Microsoft.CodeAnalysis.Rename.ConflictEngine;
|
||||
using Microsoft.CodeAnalysis.Shared.Extensions;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Roslyn.Utilities;
|
||||
using SharpIDE.Application;
|
||||
@@ -15,6 +17,7 @@ using SharpIDE.Application.Features.Run;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||
using SharpIDE.Godot.Features.Problems;
|
||||
using SharpIDE.Godot.Features.SymbolLookup;
|
||||
using SharpIDE.RazorAccess;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
using Timer = Godot.Timer;
|
||||
@@ -153,9 +156,85 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
||||
GD.Print($"Breakpoint {(breakpointAdded ? "added" : "removed")} at line {lineForDebugger}");
|
||||
}
|
||||
|
||||
private void OnSymbolLookup(string symbol, long line, long column)
|
||||
private readonly PackedScene _symbolUsagePopupScene = ResourceLoader.Load<PackedScene>("uid://dq7ss2ha5rk44");
|
||||
private void OnSymbolLookup(string symbolString, long line, long column)
|
||||
{
|
||||
GD.Print($"Symbol lookup requested: {symbol} at line {line}, column {column}");
|
||||
GD.Print($"Symbol lookup requested: {symbolString} at line {line}, column {column}");
|
||||
_ = Task.GodotRun(async () =>
|
||||
{
|
||||
var (symbol, linePositionSpan, semanticInfo) = await _roslynAnalysis.LookupSymbolSemanticInfo(_currentFile, new LinePosition((int)line, (int)column));
|
||||
if (symbol is null) return;
|
||||
|
||||
//var locations = symbol.Locations;
|
||||
|
||||
if (semanticInfo is null) return;
|
||||
if (semanticInfo.Value.DeclaredSymbol is not null)
|
||||
{
|
||||
GD.Print($"Symbol is declared here: {symbolString}");
|
||||
// TODO: Lookup references instead
|
||||
var references = await _roslynAnalysis.FindAllSymbolReferences(semanticInfo.Value.DeclaredSymbol);
|
||||
if (references.Length is 1)
|
||||
{
|
||||
var reference = references[0];
|
||||
var locations = reference.LocationsArray;
|
||||
if (locations.Length is 1)
|
||||
{
|
||||
// Lets jump to the definition
|
||||
var referenceLocation = locations[0];
|
||||
|
||||
var referenceLineSpan = referenceLocation.Location.GetMappedLineSpan();
|
||||
var sharpIdeFile = Solution!.AllFiles.SingleOrDefault(f => f.Path == referenceLineSpan.Path);
|
||||
if (sharpIdeFile is null)
|
||||
{
|
||||
GD.Print($"Reference file not found in solution: {referenceLineSpan.Path}");
|
||||
return;
|
||||
}
|
||||
await GodotGlobalEvents.Instance.FileExternallySelected.InvokeParallelAsync(sharpIdeFile, new SharpIdeFileLinePosition(referenceLineSpan.Span.Start.Line, referenceLineSpan.Span.Start.Character));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show popup to select which reference to go to
|
||||
var scene = _symbolUsagePopupScene.Instantiate<SymbolLookupPopup>();
|
||||
var locationsAndFiles = locations.Select(s =>
|
||||
{
|
||||
var lineSpan = s.Location.GetMappedLineSpan();
|
||||
var file = Solution!.AllFiles.SingleOrDefault(f => f.Path == lineSpan.Path);
|
||||
return (s, file);
|
||||
}).Where(t => t.file is not null).ToImmutableArray();
|
||||
scene.Locations = locations;
|
||||
scene.LocationsAndFiles = locationsAndFiles!;
|
||||
scene.Symbol = semanticInfo.Value.DeclaredSymbol;
|
||||
await this.InvokeAsync(() =>
|
||||
{
|
||||
AddChild(scene);
|
||||
scene.PopupCenteredClamped();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (semanticInfo.Value.ReferencedSymbols.Length is not 0)
|
||||
{
|
||||
var referencedSymbol = semanticInfo.Value.ReferencedSymbols.Single(); // Handle more than one when I run into it
|
||||
var locations = referencedSymbol.Locations;
|
||||
if (locations.Length is 1)
|
||||
{
|
||||
// Lets jump to the definition
|
||||
var definitionLocation = locations[0];
|
||||
var definitionLineSpan = definitionLocation.GetMappedLineSpan();
|
||||
var sharpIdeFile = Solution!.AllFiles.SingleOrDefault(f => f.Path == definitionLineSpan.Path);
|
||||
if (sharpIdeFile is null)
|
||||
{
|
||||
GD.Print($"Definition file not found in solution: {definitionLineSpan.Path}");
|
||||
return;
|
||||
}
|
||||
await GodotGlobalEvents.Instance.FileExternallySelected.InvokeParallelAsync(sharpIdeFile, new SharpIdeFileLinePosition(definitionLineSpan.Span.Start.Line, definitionLineSpan.Span.Start.Character));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Show a popup to select which definition location to go to
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnSymbolValidate(string symbol)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Immutable;
|
||||
using Godot;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.FindSymbols;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
|
||||
namespace SharpIDE.Godot.Features.SymbolLookup;
|
||||
|
||||
public partial class SymbolLookupPopup : PopupPanel
|
||||
{
|
||||
private Label _symbolNameLabel = null!;
|
||||
private VBoxContainer _usagesContainer = null!;
|
||||
public ImmutableArray<ReferenceLocation> Locations { get; set; }
|
||||
public ImmutableArray<(ReferenceLocation location, SharpIdeFile file)> LocationsAndFiles { get; set; }
|
||||
public ISymbol Symbol { get; set; } = null!;
|
||||
private readonly PackedScene _symbolUsageScene = ResourceLoader.Load<PackedScene>("uid://dokm0dyac2enh");
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_symbolNameLabel = GetNode<Label>("%SymbolNameLabel");
|
||||
_symbolNameLabel.Text = "";
|
||||
_usagesContainer = GetNode<VBoxContainer>("%UsagesVBoxContainer");
|
||||
_usagesContainer.GetChildren().ToList().ForEach(s => s.QueueFree());
|
||||
AboutToPopup += OnAboutToPopup;
|
||||
|
||||
_usagesContainer.GetChildren().ToList().ForEach(s => s.QueueFree());
|
||||
foreach (var (location, file) in LocationsAndFiles)
|
||||
{
|
||||
var resultNode = _symbolUsageScene.Instantiate<SymbolUsageComponent>();
|
||||
resultNode.Location = location;
|
||||
resultNode.File = file;
|
||||
resultNode.ParentSearchWindow = this;
|
||||
_usagesContainer.AddChild(resultNode);
|
||||
}
|
||||
_symbolNameLabel.Text = $"'{Symbol.Name}'";
|
||||
}
|
||||
|
||||
private void OnAboutToPopup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cxxo2sex03ox5
|
||||
@@ -0,0 +1,64 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://dq7ss2ha5rk44"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cxxo2sex03ox5" path="res://Features/SymbolLookup/SymbolLookupPopup.cs" id="1_f5udm"]
|
||||
[ext_resource type="PackedScene" uid="uid://dokm0dyac2enh" path="res://Features/SymbolLookup/SymbolUsageComponent.tscn" id="1_k5g0h"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cuaw5"]
|
||||
bg_color = Color(0.1764706, 0.1764706, 0.1764706, 1)
|
||||
corner_radius_top_left = 5
|
||||
corner_radius_top_right = 5
|
||||
corner_radius_bottom_right = 5
|
||||
corner_radius_bottom_left = 5
|
||||
shadow_color = Color(0, 0, 0, 0.11764706)
|
||||
shadow_size = 4
|
||||
|
||||
[node name="SymbolLookupPopup" type="PopupPanel"]
|
||||
oversampling_override = 1.0
|
||||
size = Vector2i(505, 340)
|
||||
visible = true
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_cuaw5")
|
||||
script = ExtResource("1_f5udm")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 4.0
|
||||
offset_top = 4.0
|
||||
offset_right = -4.0
|
||||
offset_bottom = -4.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 15
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_right = 15
|
||||
theme_override_constants/margin_bottom = 5
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 43.615)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Usages of"
|
||||
|
||||
[node name="SymbolNameLabel" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "'UseWebApi()'"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
follow_focus = true
|
||||
|
||||
[node name="UsagesVBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SymbolUsageComponent" parent="MarginContainer/VBoxContainer/ScrollContainer/UsagesVBoxContainer" instance=ExtResource("1_k5g0h")]
|
||||
layout_mode = 2
|
||||
@@ -0,0 +1,53 @@
|
||||
using Godot;
|
||||
using Microsoft.CodeAnalysis.FindSymbols;
|
||||
using SharpIDE.Application.Features.Analysis;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
|
||||
namespace SharpIDE.Godot.Features.SymbolLookup;
|
||||
|
||||
public partial class SymbolUsageComponent : MarginContainer
|
||||
{
|
||||
private Label _enclosingSymbolLabel = null!;
|
||||
private Label _fileNameLabel = null!;
|
||||
private Label _lineNumberLabel = null!;
|
||||
private Button _button = null!;
|
||||
|
||||
public SymbolLookupPopup ParentSearchWindow { get; set; } = null!;
|
||||
public ReferenceLocation? Location { get; set; }
|
||||
public SharpIdeFile File { get; set; } = null!;
|
||||
|
||||
[Inject] private readonly RoslynAnalysis _roslynAnalysis = null!;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_button = GetNode<Button>("Button");
|
||||
_enclosingSymbolLabel = GetNode<Label>("%EnclosingSymbolLabel");
|
||||
_fileNameLabel = GetNode<Label>("%FileNameLabel");
|
||||
_lineNumberLabel = GetNode<Label>("%LineNumberLabel");
|
||||
SetValue(Location);
|
||||
_button.Pressed += OnButtonPressed;
|
||||
}
|
||||
|
||||
private void OnButtonPressed()
|
||||
{
|
||||
var mappedLineSpan = Location!.Value.Location.GetMappedLineSpan();
|
||||
var fileLinePosition = new SharpIdeFileLinePosition { Line = mappedLineSpan.StartLinePosition.Line, Column = mappedLineSpan.StartLinePosition.Character };
|
||||
GodotGlobalEvents.Instance.FileExternallySelected.InvokeParallelFireAndForget(File, fileLinePosition);
|
||||
ParentSearchWindow.Hide();
|
||||
}
|
||||
|
||||
private void SetValue(ReferenceLocation? result)
|
||||
{
|
||||
if (result is null) return;
|
||||
var mappedLineSpan = result.Value.Location.GetMappedLineSpan();
|
||||
|
||||
_fileNameLabel.Text = File.Name;
|
||||
_lineNumberLabel.Text = (mappedLineSpan.StartLinePosition.Line + 1).ToString();
|
||||
|
||||
_ = Task.GodotRun(async () =>
|
||||
{
|
||||
var enclosingSymbol = await _roslynAnalysis.GetEnclosingSymbolForReferenceLocation(result.Value);
|
||||
await this.InvokeAsync(() => _enclosingSymbolLabel.Text = enclosingSymbol?.Name);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ct037eoc26o04
|
||||
@@ -0,0 +1,62 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://dokm0dyac2enh"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ct037eoc26o04" path="res://Features/SymbolLookup/SymbolUsageComponent.cs" id="1_f7dno"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6ov2c"]
|
||||
draw_center = false
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dtmd4"]
|
||||
bg_color = Color(0.18039216, 0.2627451, 0.43137255, 1)
|
||||
corner_radius_top_left = 3
|
||||
corner_radius_top_right = 3
|
||||
corner_radius_bottom_right = 3
|
||||
corner_radius_bottom_left = 3
|
||||
|
||||
[node name="SymbolUsageComponent" type="MarginContainer"]
|
||||
anchors_preset = 14
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_top = -4.0
|
||||
offset_bottom = 4.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_f7dno")
|
||||
|
||||
[node name="Button" type="Button" parent="."]
|
||||
custom_minimum_size = Vector2(0, 26)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_6ov2c")
|
||||
theme_override_styles/focus = SubResource("StyleBoxFlat_dtmd4")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="Button"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_right = 5
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Button/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="EnclosingSymbolLabel" type="Label" parent="Button/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Containing Symbol Name"
|
||||
text_overrun_behavior = 3
|
||||
|
||||
[node name="FileNameLabel" type="Label" parent="Button/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 0.7411765)
|
||||
text = "FileName.cs"
|
||||
|
||||
[node name="LineNumberLabel" type="Label" parent="Button/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 0.7411765)
|
||||
text = "24"
|
||||
Reference in New Issue
Block a user