В этом материале Костя расскажет, как настроить сниппеты — небольшие фрагменты кода, которые можно сохранить в каталог и вставлять по поисковому слову. Если у вас есть какой-то код, который часто повторяете, то его можно добавить в виде сниппета и не печатать каждый раз.

Автор материала

Статью написал Костя @say_hey_to_k — БИМ-специалист из Китая. Он работает на канадскую фирму и, кроме Ревита, занимается также и программированием.

Это третья часть из материала о настройки VSCode, первая была про установку и настройку интерфейса VSCode. Вторая — про подсказки при работе с кодом.

Пример

В предыдущих статьях писал подсказку типа для переменных и методов. Я не писал всю подсказку каждый раз. Как только я начинаю вбивать ty, VSCode мне предлагает два варианта: один для метода, другой - для переменной. После того как я выберу тип подсказки, он вставляет нужную часть текста. А дальше я дописываю типы. Удобно это или нет — решать вам.

Создание файла со сниппетами

Нажимаем Ctr+Shift+P, там вбиваем «snippet» и выбираем «Фрагменты кода: Настройка фрагментов». Если файл со сниппетами у вас уже есть, то предложит его выбрать. Если нет, предложит создать. Выбираем Python.

VSCode создаст нам json файл с закомментированным примером и описанием сниппета.

Если хотите добавить сниппеты для подсказок типа, замените всё следующим кодом и сохранитесь:

{
    "Method type comment": {
        "prefix": "type for method",
        "body": "# type: ($1) -> ${2:None}",
        "description": "Adds method type comment in py2 style."
    },
    "Variable type comment": {
        "prefix": "type for variable",
        "body": "# type: ",
        "description": "Adds variable type comment in py2 style."
    },
}

Краткое описание того, что находится в файле сниппетов:

По умолчанию сниппет не всегда будет на самом верху подсказок:

Если хочется, чтобы сниппеты были всегда наверху, идём в параметры VSCode, там вбиваем «snippet suggestions» и выбираем top:

Создание своего сниппета

Если сниппет — простой однострочный текст, то заходим в файл сниппетов, дублируем предыдущий и заполняем необходимые поля. Не игнорируйте подчёркивания ошибок. Возможно, вы накосячили с синтаксисом. Он вам подскажет, если где-то пропущена скобочка, стоит лишняя запятая или ещё чего.

Если сниппет многострочный, можно его предварительно сгенерировать при помощи онлайн сервиса, например snippet-generator. Также в каталоге расширений есть различные плагины для генерации и управления сниппетами. Я использую Easy Snippet. Но это уже излишество. Напомню, чем меньше расширений, тем лучше.

Можно выбирать, как вставляется сниппет, куда переместится курсор при его создании (как например, у меня в сниппете подсказки для метода), сгенерировать всякую инфу и многое другое. Про всё это можно прочитать в справке.

Импорты

Знакомая картина?

Мы создаём мегашаблон с импортами на все случаи жизни, с которого начинаем кодить. Обещаем себе удалить неиспользуемые импорты потом. А может и нет. Зачем?

В итоге каждый раз открывая файл, чтобы добраться до кода, нам нужно промотать всю эту бесполезную простыню. А потом ещё ловим непонятные ошибки вроде «Line object has no attribute ‘CreateBound’».

При работе в VSCode от такой практики можно отказаться, используя подсказки и сниппеты.

Стандартные библиотеки (типа os, re, itertools и даже System.Collections.Generic) VSCode будет и так предлагать импортировать. Часто встречающиеся апишные импорты можно добавлять сниппетами по надобности.

Сначала рассмотрим один пример с самым распространённым импортом. Добавим следующий сниппет и сохранимся:

"Import Autodesk Revit DB": {
    "prefix": "import db",
    "body": [
        "clr.AddReference(\"RevitAPI\")",
        "from Autodesk.Revit.DB import *",
        ""
    ],
    "description": "Imports Autodesk.Revit.DB"
}

Если в коде начнём вбивать “import” или “db”, он его предложит:

Сам я против импорта звёздочки. По многим причинам. У себя в коде стараюсь использовать хотя бы from Autodesk.Revit import DB. Но также знаю, что в динамовских скриптах это очень распространённая практика. Переучивать никого не собираюсь.

Теперь выкатим все сниппеты сразу (можете заменить ими всё в файле со сниппетами или использовать только часть):

{
    "Method type comment": {
        "prefix": "type for method",
        "body": "# type: ($1) -> ${2:None}",
        "description": "Adds method type comment in py2 style."
    },
    "Variable type comment": {
        "prefix": "type for variable",
        "body": "# type: ",
        "description": "Adds variable type comment in py2 style."
    },
    "UnwrapElement": {
        "prefix": "UnwrapElement",
        "body": "UnwrapElement(IN[$1])",
        "description": "Adds UnwrapElement(IN[])"
    },
    "Import Autodesk Revit DB": {
        "prefix": "import db",
        "body": [
            "clr.AddReference(\"RevitAPI\")",
            "from Autodesk.Revit.DB import *",
            ""
        ],
        "description": "Imports Autodesk.Revit.DB"
    },
    "Import Dynamo Revit Nodes ": {
        "prefix": "import dynamo elements",
        "body": [
            "clr.AddReference(\"RevitNodes\")",
            "from Revit.Elements import *",
            ""
        ],
        "description": "Imports Dynamo Node Revit Elements"
    },
    "Import Dynamo Element Wrapper Extension": {
        "prefix": "import element wrapper",
        "body": [
            "import Revit",
            "clr.ImportExtensions(Revit.Elements)",
            ""
        ],
        "description": [
            "Imports ToDSType(bool) extension method.",
            "",
            "Requires imported RevitNodes: clr.AddReference(\"RevitNodes\")",
            ""
        ]
    },
    "Import Dynamo Geometry Wrapper Extension": {
        "prefix": "import geometry wrapper",
        "body": [
            "import Revit",
            "clr.ImportExtensions(Revit.GeometryConversion)",
            ""
        ],
        "description": [
            "Imports ToProtoType(), ToRevitType() geometry extension methods.",
            "",
            "Requires imported RevitNodes: clr.AddReference(\"RevitNodes\")",
            ""
        ]
    },
    "Import Dynamo Proto Geometry": {
        "prefix": "import dynamo proto geometry",
        "body": [
            "clr.AddReference(\"ProtoGeometry\")",
            "from Autodesk.DesignScript.Geometry import *",
            ""
        ],
        "description": "Imports Dynamo Proto Geometry"
    },
    "Import Dynamo RevitServices": {
        "prefix": "import doc tran manager",
        "body": [
            "clr.AddReference(\"RevitServices\")",
            "from RevitServices.Persistence import DocumentManager",
            "from RevitServices.Transactions import TransactionManager",
            ""
        ],
        "description": [
            "Imports Dynamo Revit Services",
            "(DocumentManager and TransactionManager)",
            ""
        ]
    },
    "CurrentDBDocument": {
        "prefix": "doc",
        "body": [
            "doc = DocumentManager.Instance.CurrentDBDocument",
            ""
        ],
        "description": [
            "Assigns CurrentDBDocument to variable doc",
            "",
            "Requires imported RevitServices and DocumentManager from RevitServices",
            ""
        ]
    },
    "CurrentUIApplication": {
        "prefix": "uiapp",
        "body": [
            "uiapp = DocumentManager.Instance.CurrentUIApplication",
            ""
        ],
        "description": [
            "Assigns CurrentUIApplication to variable uiapp",
            "",
            "Requires imported RevitServices and DocumentManager from RevitServices",
            ""
        ]
    },
    "CurrentUIApplication Application": {
        "prefix": "app",
        "body": [
            "app = DocumentManager.Instance.CurrentUIApplication.Application",
            ""
        ],
        "description": [
            "Assigns CurrentUIApplication.Application to variable app",
            "",
            "Requires imported RevitServices and DocumentManager from RevitServices",
            ""
        ]
    }
}

Как с этим работать (когда привыкнете, ваша скорость будет намного выше):

Логика следующая: вы не храните абсолютно всё в шаблоне. В шаблоне должно быть только то, с чего начинается 99 % вашего любого кода. Импорты добавляете сниппетами по надобности, вбивая любую часть триггер-слова. Триггеры у сниппетов могут повторяться. По подсказкам можно листать, читая подробные описания (если вы их туда добавили). Все подсказки можно вывести, нажав Ctrl + Пробел.

Возможно, по иллюстрации вы заметили, что я добавил сниппет «UnwrapElement». Можете подумать, какие ещё часто встречающиеся куски кода у вас есть и записать их в сниппеты.

Удачи!