Всем привет! На связи Глеб Гусаров, flutter-разработчик в команде aim digital. Мы занимаемся разработкой цифровых продуктов и сервисов и автоматизацией процессов для бизнеса. В статье рассказываю, как создать файл конфигурации сниппетов и делюсь своей подборкой полезных сниппетов.
Snippet — это шаблон (подсказка в коде), по вызову которого можно быстро вставить готовый код.
В файле конфигурации сниппет представляет собой сущность в JSON имеющую ключ состоящую из двух полей:
-
поле prefix — тип данных String — ключевое слово, при написании которого будет предложено использовать snippet
-
поле body — массив String — код, который будет вставлен после применения snippet'a
Пример snippet'a :
"localizationImport": {
"prefix": "localizationImport",
"body": [
"import 'package:perfluence_app/generated/l10n.dart';",
],
}
Специальные возможности и регулярные выражения в snippet'ах
"t" — табуляция.
"$1" — место куда будет поставлен курсор после применения snippet'a, можно использовать $2, $3 и т.д. Цифра — это очередность позиции, куда встанет курсор после нажатия на Tab.
"$TM_FILENAME_BASE" — обращение к названию файла без расширения.
"${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}" — вернет название файла в CamelCase.
Как создать файл конфигурации Snippet'ов
-
В Visual Studio code нажать комбинацию клавиш cmnd(ctrl) + shift + p
-
В появившемся поле ввести — Snippets
-
Выбрать в выпадающем меню пункт Preferences: Configure User Snippets и нажать Enter
-
Выбрать расширение файла, для которого будут использованы Snippet'ы (В нашем случае файлы с расширением .dart). После чего создастся json-файл конфигурации Snippet'ов.
Примеры полезных сниппетов
Шаблон для дата классов (десериализация json_annotation + equatable)
"dataClassFrom": {
"prefix": "dataClassFrom",
"body": [
"import 'package:equatable/equatable.dart';",
"import 'package:json_annotation/json_annotation.dart';",
"",
"part '$TM_FILENAME_BASE.g.dart';",
"",
"@JsonSerializable(",
"tfieldRename: FieldRename.snake,",
"tcreateToJson: false,",
")",
"",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g} extends Equatable{",
"tconst ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}();",
"",
"tfactory ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}.fromJson(Map<String, dynamic> json) => _$${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}FromJson(json);",
"",
"t$1",
"",
"t@override",
"tList<Object?> get props => [];",
"}",
]
},
Шаблон для дата классов (десериализация, сериализация json_annotation + equatable)
"dataClassToFrom": {
"prefix": "dataClassToFrom",
"body": [
"import 'package:equatable/equatable.dart';",
"import 'package:json_annotation/json_annotation.dart';",
"",
"part '$TM_FILENAME_BASE.g.dart';",
"",
"@JsonSerializable(",
"tfieldRename: FieldRename.snake,",
")",
"",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g} extends Equatable{",
"tconst ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}();",
"",
"tfactory ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}.fromJson(Map<String, dynamic> json) => _$${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}FromJson(json);",
"",
"tMap<String, dynamic> toJson() => _$${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}ToJson(this);",
"",
"t$1",
"",
"t@override",
"tList<Object?> get props => [];",
"}",
]
},
Шаблон Stateless widget
"stateless": {
"prefix": "stless",
"body": [
"import 'package:flutter/material.dart';",
"",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/} extends StatelessWidget {",
"t@override",
"tWidget build(BuildContext context) {",
"ttreturn $1;",
"t}",
"}",
]
},
Шаблон Statefull widget
"statefull": {
"prefix": "stfull",
"body": [
"import 'package:flutter/material.dart';",
"",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/} extends StatefulWidget {",
"t@override",
"tState<${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}> createState() => _${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}State();",
"}",
"",
"class _${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}State extends State<${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}> {",
"t@override",
"tWidget build(BuildContext context) {",
"ttreturn $2;",
"t}",
"}",
]
},
Шаблон для быстрого создания цвета из HEX
"color": {
"prefix": "color",
"body": "const Color(0xFF$1)",
},
Шаблон для быстрого создания BoxShadow
"boxShadow": {
"prefix": "bsh",
"body": [
"BoxShadow(",
"tcolor: Colors.black.withOpacity(.5),",
"toffset: const Offset(0, 0),",
"tblurRadius: 0,",
"),"
]
},
Шаблон для написания тестов arrange, act, assert
"aaaTest": {
"prefix": "aaaTest",
"body": [
"test(",
"t'should $1',",
"t() async {",
"t//arrange",
"t$2",
"t//act",
"t",
"t//assert",
"t},",
");",
],
},
Шаблон для создания интерфейса репозитория
"repo": {
"prefix": "repo",
"body": [
"import '/core/error/failures.dart';",
"import 'package:dartz/dartz.dart';",
"",
"abstract class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g} {",
"t$2",
"}",
],
},
Шаблон для написания имплементации репозитория
"repoImpl": {
"prefix": "repoImpl",
"body": [
"import 'package:dartz/dartz.dart';",
"import '/core/error/failures.dart';",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g} implements $1 {",
"t@override",
"tFuture<Either<Failure, $2>> getConcreteNumberTrivia() async {",
"ttreturn const Left(DefaultFailure());",
"t}",
"}",
],
},
Шаблон для создания дата-класса параметров usecase
"usecaseParams": {
"prefix": "usecaseParams",
"body": [
"import 'package:dartz/dartz.dart';",
"import 'package:equatable/equatable.dart';",
"import '/core/error/failures.dart';",
"import '/core/usecases/usecase.dart';",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}UC implements UseCase<$1, ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}Params> {",
"tconst ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}UC(this.repo);",
"",
"tfinal $2 repo;",
"",
"t@override",
"tFuture<Either<Failure, $1>> call(${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}Params params) async {",
"ttreturn await repo.$3();",
"t}",
"}",
"",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}Params extends Equatable {",
"tconst ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}Params();",
"t@override",
"tList<Object?> get props => [];",
"}",
]
},
Автор: aim digital