File: CommonControls\NewTypeDestinationSelectionViewModel.cs
Web Access
Project: src\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_ozsccwvc_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.Implementation.CommonControls;
 
internal class NewTypeDestinationSelectionViewModel : AbstractNotifyPropertyChanged
{
    public static NewTypeDestinationSelectionViewModel Default = new(
        string.Empty,
        LanguageNames.CSharp,
        string.Empty,
        string.Empty,
        ImmutableArray<string>.Empty,
        null
    );
 
    private readonly string _fileExtension;
    private readonly string _defaultNamespace;
    private readonly string _generatedNameTypeParameterSuffix;
    private readonly ImmutableArray<string> _conflictingNames;
    private readonly string _defaultName;
    private readonly ISyntaxFactsService? _syntaxFactsService;
    private readonly string _languageName;
 
    public NewTypeDestinationSelectionViewModel(
        string defaultName,
        string languageName,
        string defaultNamespace,
        string generatedNameTypeParameterSuffix,
        ImmutableArray<string> conflictingNames,
        ISyntaxFactsService? syntaxFactsService)
    {
        _defaultName = defaultName;
        _fileExtension = languageName == LanguageNames.CSharp ? ".cs" : ".vb";
        _languageName = languageName;
        _generatedNameTypeParameterSuffix = generatedNameTypeParameterSuffix;
        _conflictingNames = conflictingNames;
        _defaultNamespace = defaultNamespace;
        _typeName = _defaultName;
        _syntaxFactsService = syntaxFactsService;
        _fileName = $"{defaultName}{_fileExtension}";
    }
 
    private string _typeName;
    public string TypeName
    {
        get
        {
            return _typeName;
        }
 
        set
        {
            if (SetProperty(ref _typeName, value))
            {
                FileName = string.Format("{0}{1}", value.Trim(), _fileExtension);
                NotifyPropertyChanged(nameof(GeneratedName));
            }
        }
    }
 
    public string GeneratedName
    {
        get
        {
            return string.Format(
                "{0}{1}{2}",
                string.IsNullOrEmpty(_defaultNamespace) ? string.Empty : _defaultNamespace + ".",
                _typeName.Trim(),
                _generatedNameTypeParameterSuffix);
        }
    }
 
    private string _fileName;
    public string FileName
    {
        get { return _fileName; }
        set { SetProperty(ref _fileName, value); }
    }
 
    private NewTypeDestination _destination = NewTypeDestination.NewFile;
    public NewTypeDestination Destination
    {
        get { return _destination; }
        set
        {
            if (SetProperty(ref _destination, value))
            {
                NotifyPropertyChanged(nameof(FileNameEnabled));
            }
        }
    }
 
    internal bool TrySubmit([NotNullWhen(returnValue: false)] out string? message)
    {
        message = null;
 
        if (_syntaxFactsService is null)
        {
            throw new InvalidOperationException();
        }
 
        var trimmedName = TypeName.Trim();
        if (_conflictingNames.Contains(trimmedName))
        {
            message = ServicesVSResources.Name_conflicts_with_an_existing_type_name;
            return false;
        }
 
        if (!_syntaxFactsService.IsValidIdentifier(trimmedName))
        {
            message = string.Format(ServicesVSResources.Name_is_not_a_valid_0_identifier, _languageName);
            return false;
        }
 
        var trimmedFileName = FileName.Trim();
        if (!Path.GetExtension(trimmedFileName).Equals(_fileExtension, StringComparison.OrdinalIgnoreCase))
        {
            message = string.Format(ServicesVSResources.File_name_must_have_the_0_extension, _fileExtension);
            return false;
        }
 
        if (trimmedFileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
        {
            message = ServicesVSResources.Illegal_characters_in_path;
            return false;
        }
 
        return true;
    }
 
    public bool FileNameEnabled => Destination == NewTypeDestination.NewFile;
}
 
internal enum NewTypeDestination
{
    CurrentFile,
    NewFile
};