microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
162.68k stars 28.69k forks source link

CSHTML Razor syntax highlighting suboptimal #225246

Open sitefinitysteve opened 1 month ago

sitefinitysteve commented 1 month ago

Does this issue occur when all extensions are disabled?: Yes

Steps to Reproduce:

  1. Open .cshtml with Model\Razor syntax

Razor syntax is off in VSCode vs Visual Studio

Here's VSCode image

Here's VS2022 image

It's much much harder to do anything in Razor with VSCode.

Even things like this, that model directive is just invisible

image

vs-code-engineering[bot] commented 1 month ago

Thanks for creating this issue! It looks like you may be using an old version of VS Code, the latest stable release is 1.92.1. Please try upgrading to the latest version and checking whether this issue remains.

Happy Coding!

alexr00 commented 1 month ago

There are some other differences, but in your screenshots this is the only one that looks to be categorically worse:

Image

Could you share a code snippet?

sitefinitysteve commented 1 month ago

@alexr00 Yep!

Util just being a static helper class...

@model SitefinityWebApp.Mvc.Models.ProSearch.ProSearchModel

@using Telerik.Sitefinity.Frontend.Mvc.Helpers;
@using Telerik.Sitefinity.Modules.Pages;
@using SitefinityWebApp

@Html.Partial("/Mvc/Views/Shared/KendoVueWrappers/Dropdowns.cshtml")
@Html.StyleSheet("https://cdn.jsdelivr.net/npm/vue2-autocomplete-js@0.2.2/dist/style/vue2-autocomplete.min.css", "head")

@Html.Script("https://cdn.jsdelivr.net/npm/he@1.2.0/he.min.js", "plugins")
@Html.Script("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js", "plugins")
@Html.Script("/Mvc/Views/ProSearch/Resources/prosearch-vue.js?v=" + Util.OapConfig.StyleScriptVersion, "bottom")

<script>
    var $tools = @Html.Raw(Model.SerializedDatabases);

    var $query = {
        search: "@(Request.QueryString["search"])",
        db: "@(Request.QueryString["db"])",
        type: "@(Model.SearchType)"
    };

    var $labels = {
        searchPlaceholder: "@Util.GetOAPResource("SearchPlaceholder")",
        loadMore: "@Html.Resource("LoadMoreResultsButton")",
        didYouMean: "@Util.GetOAPResource("DidYouMean")",
        youreSearchingThe: "@Util.GetOAPResource("YoureSearchingThe")",
        clearFilters: "@Util.GetOAPResource("ClearFilters")",
        loading: "@Util.GetOAPResource("Loading")",
        notFinding: "@Util.GetOAPResource("NotFinding")",
        lookOtherDB: "@Util.GetOAPResource("LookOtherDB")",
        medlinePlus: "@Util.GetOAPResource("MedlinePlus")",
        cantFindIr: "@Util.GetOAPResource("cant_find_ir")",
    };
</script>

<div id="prosearch-vue" class="prosearch-wrapper @Model.SearchType" v-cloak style="min-height: 600px">
    <div class="ps-prosearch-top">
        <div class="container">
            <div class="row mt-4">
                <div class="col-md-12">
                    <div class="form-horizontal">
                        <div class="form-group">
                            <div class="col-sm-8">
                                <div class="input-group">
                                    <kendo-autocomplete
                                        id="searchAutoComplete"
                                        ref="autocomplete"
                                        v-model="selected.searchQuery"
                                        :data-source="autocompleteDataSource"
                                        :placeholder="labels.searchPlaceholder"
                                        :disabled="isSearching"
                                        :min-length="3"
                                        @@select="onAutocompleteSelect"
                                        @@change="onAutocompleteChange"
                                        class="form-control input-lg searchField pro"
                                    >
                                    </kendo-autocomplete>
                                    <!--<input type="text" v-model="selected.searchQuery" class="form-control input-lg" :placeholder="labels.searchPlaceholder" :disabled="isSearching" v-on:keyup.enter="onSearchClick">-->
                                   <span class="input-group-btn">
                                        <button class="btn btn-primary btn-lg" type="button" v-on:click="onSearchClick" :disabled="isSearching">
                                            <i class="fas fa-search" v-if="!isSearching"></i>
                                            <i class="fas fa-spinner fa-spin" v-if="isSearching"></i>
                                        </button>
                                    </span>
                                </div>
                            </div>
                            <div class="col-sm-4">
                                <div class="dropdown">
                                    <button class="btn btn-secondary btn-lg dropdown-toggle border" type="button" id="databaseDropdown" :disabled="isSearching" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" style="width: 100%; text-align: left;">
                                        <i :class="selected.database.icon"></i> {{ selected.database.Name }}
                                        <span class="caret" style="float: right; margin-top: 8px;"></span>
                                    </button>
                                    <ul class="dropdown-menu" aria-labelledby="databaseDropdown" style="width: 100%;">
                                        <li class="font-lg" v-for="item in menuItems" :key="item.InternalCode">
                                            <a href="#" v-on:click.prevent="selectDatabase(item)" class="py-2">
                                                <i :class="item.icon" class="fa-fw pr-2"></i> {{ item.Name }}
                                            </a>
                                        </li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <nav class="navbar navbar-default" v-if="selected.database.Filters.length > 0">
        <div class="container">
            <ul class="nav navbar-nav">
                <li v-for="filter in selected.database.Filters" :key="filter.Name" class="dropdown auto-size-dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
                        {{ filter.Name }} <span class="caret"></span>
                    </a>
                    <ul class="dropdown-menu">
                        <li v-for="option in filter.Options" :key="option.Value">
                            <label>
                                <input 
                                    type="checkbox" 
                                    :checked="option.Selected"
                                    v-on:change="updateFilter(filter, option)"
                                    v-on:click.stop
                                >
                                {{ option.Name }}
                            </label>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </nav>

    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="ps-search-results-wrap row">
                    <div class="results-section col-md-8">
                        <div v-if="searchError" class="alert alert-danger mt-3">
                            {{ searchError }}
                        </div>

                        <div class="did-you-mean" v-if="spellingSuggestion">
                            {{ labels.didYouMean }} <span v-on:click="useSpellingSuggestion">{{ spellingSuggestion }}</span>
                        </div>
                        <div class="well my-4 py-2 bg-white">
                            <h4 class="">
                                {{ labels.youreSearchingThe | decodeHTML }} <span class="database-selected text-primary">{{ selected.database.Name }}</span>.
                            </h4>
                            <div class="search-details mt-2">{{ selected.searchDetails }}</div>
                        </div>
                        <div class="filter-box" v-if="hasFilters">
                            <div class="filters my-4">
                                <span v-for="(filter, filterIndex) in selected.searchFilters" :key="filterIndex" class="">
                                    {{ filter.name }}:
                                    <span v-for="(option, optionIndex) in filter.options" :key="optionIndex" class="ml-1 badge badge-primary mr-2 mb-2">
                                        {{ option }}
                                        <button @@click.stop="removeFilterOption(filter, option)" 
                                                class="btn btn-sm btn-link text-white" 
                                                aria-label="Remove filter">
                                            <i class="fas fa-times"></i>
                                        </button>
                                    </span>
                                </span>
                            </div>
                            <button class="btn btn-primary btn-sm clear-filters" v-on:click="onClearFilters">{{ labels.clearFilters }}</button>
                        </div>
                        <div class="results-loading" v-if="isSearching">
                             <ul class="results-ul">
                                <li class="result-item mb-4 pt-4" v-for="n in 5" :key="n">
                                    <div class="title mb-2">
                                        <span class="placeholder placeholder-lg placeholder-glow" style="background-color: #3f84ae"></span>
                                    </div>
                                    <p>
                                        <span class="placeholder placeholder-sm placeholder-glow w-75"></span>
                                        <span class="placeholder placeholder-sm placeholder-glow w-75"></span>
                                        <span class="placeholder placeholder-sm placeholder-glow w-50"></span>
                                    </p>
                                </li>
                            </ul>
                        </div>
                        <ul class="results-ul" v-else>
                            <li v-for="item in data" :key="item.Id" class="result-item">
                                <div class="title">
                                    <a :href="item.Url">{{ item.Title }}</a>
                                </div>
                                <p v-html="item.Summary"></p>
                                <div class="info-section clearfix">
                                    <div class="category">{{ item.SubTitle }}</div>
                                    <div class="rating">
                                        <ul :class="'rank' + item.Rating">
                                            <li v-for="n in 5" :key="n" :class="'star' + n"><i class="icon-star"></i></li>
                                        </ul>
                                    </div>
                                </div>
                            </li>
                        </ul>
                        <div class="medline-plus" v-if="medlineplus">
                            {{ labels.notFinding | decodeHTML }} {{ labels.lookOtherDB }}
                            <a href="#" v-on:click.prevent="onMedlinePlusClick">{{ labels.medlinePlus }}<i class="icon-external-link"></i></a>
                        </div>
                        <div class="excluded-websites medline-plus" v-if="excluded_websites" v-html="labels.cantFindIr">
                        </div>
                        <button class="btn btn-default load-more-results" v-if="canLoadMore" v-on:click="loadMoreResults">
                            <span v-if="!isSearching">{{ loadMoreText }}</span>
                            <i class="icon-refresh icon-spin" v-if="isSearching"></i>
                        </button>
                    </div>
                    <div class="overview-section col-md-4">
                        <div class="overview-section-inner my-4">
                            <div class="no-article-selected animated" v-if="searchExists">
                                <h3>{{ labels.notFinding | decodeHTML }}</h3>
                                <p>{{ labels.lookOtherDB }}</p>
                                <ul>
                                    <li v-for="db in currentSearch" :key="db.Database" class="sidebar-db-search" :class="['count' + db.Count, db.Database]" :data-db="db.DisplayOrder" :data-count="db.Count" :data-url="db.SearchUrl" v-on:click="onSidebarDbClick(db)">
                                        <i :class="['prosearchsprite', 'icon-' + db.Database, 'mr-2']"></i>
                                        <span>{{ db.Count }}</span> {{ db.DatabaseTitle }}
                                    </li>
                                </ul>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <input type="hidden" id="searchBackState" value="" />
</div>

@if (Model.Databases.Count == 0 && Util.IsDev)
{
    <div class="p-4 my-5 mx-5 bg-danger border">
        No Databases returned
    </div>
}

image

sitefinitysteve commented 1 month ago

Makes me not want to work with Razor in VSCode...

alexr00 commented 1 month ago

Thanks for the sample!

I was hoping there were already tokens that we could update our themes to color differently, but it looks like we'll need to start another razor block within the JS block when we see "@.

sitefinitysteve commented 1 month ago

Thank you for caring!

What about in the class attr there in the middle on the id=prosearch-vue as well, is that already handled?

RedCMD commented 1 month ago

hmmm.... this looks like fun those strings are handled by the javascript grammar

prob have to make an injection into: string.quoted.double.js meta.object.member.js meta.objectliteral.js meta.var.expr.js source.js meta.embedded.block.html text.html.cshtml

and is that meta.objectliteral.js missing a .?