Основные возможности Cursor IDE
- Главное - это AI чат-помощник с поддержкой русского языка (с помощью него можно задавать вопросы и вносить правки в код)
- Автодополнение и подсказки 1С
- Автоматический рефакторинг (может внести изменения в код и обосновать, почему так сделал, переименование переменных и т.п.)
- Проверка качества кода 1С (поиск узких мест, ошибки и т.п.).
Подготовка 1С
- Выгружаем код конфигурации 1С в файлы в папку (Конфигурация - Выгрузить конфигурацию в файлы)
Подготовка Cursor IDE
- Скачиваем и устанавливаем Cursor IDE с сайта (без VPN и регистрации 🙃)
- Для удобства навигации по метаданным 1С ставим плагин
- Для подсветки синтаксиса 1С как вариант ставим плагин
- Опционально можно поставить плагин для выбора темы оформления
Работа в Cursor IDE
Запускаем и выбираем папку с файлами конфигурации
Работа с AI чат - помощником
- Открываем нужный файл с кодом
- Пишем текстом в AI чате, что хотим сделать с кодом/проверить
Пример 1. Рефакторинг к стандартам 1С
Псевдо-код расчета вознаграждения менеджерам
Промт-запросы в AI чате:
- Добавь комментарии к коду
- Сделай рефакторинг, учти стандарты от 1С и алгоритмическую сложность
Код до рефакторинга
Перем ТаблицаПродаж; // Глобальная переменная (риск утечки памяти)
// Рассчитывает вознаграждение менеджеров (плохой пример)
Функция РассчитатьВознаграждения_Плохо(Месяц, Год)
// Каждый раз загружает все продажи (медленно)
ТаблицаПродаж = ПолучитьПродажиЗаПериод(Месяц, Год); // Нет кеширования
// Создаём таблицу для результатов (лишний расход памяти)
ТаблицаРезультатов = Новый ТаблицаЗначений;
ТаблицаРезультатов.Колонки.Добавить("Менеджер");
ТаблицаРезультатов.Колонки.Добавить("Вознаграждение");
// Проходим по всем менеджерам (O(n))
Для каждого Менеджер Из Справочники.Менеджеры.Выбрать() Цикл
СуммаПродаж = 0;
// Вложенный цикл по продажам (O(n²)) – медленно!
Для каждого СтрокаПродажи Из ТаблицаПродаж Цикл
Если СтрокаПродажи.Менеджер = Менеджер.Ссылка Тогда
СуммаПродаж = СуммаПродаж + СтрокаПродажи.Сумма;
КонецЕсли;
КонецЦикла;
// Жёстко закодированные проценты (негибко)
Если СуммаПродаж > 1000000 Тогда
Процент = 0.1;
ИначеЕсли СуммаПродаж > 500000 Тогда
Процент = 0.07;
Иначе
Процент = 0.05;
КонецЕсли;
Вознаграждение = СуммаПродаж * Процент;
// Добавляем результат
НоваяСтрока = ТаблицаРезультатов.Добавить();
НоваяСтрока.Менеджер = Менеджер.Наименование;
НоваяСтрока.Вознаграждение = Вознаграждение;
КонецЦикла;
Возврат ТаблицаРезультатов;
КонецФункции
Код после рефакторинга
// Быстрый расчёт с группировкой и кешированием
Функция РассчитатьВознаграждения_Оптимально(Месяц, Год)
// Кешируем запрос, если данные уже загружались
СтатическиеДанные = Неопределено;
Если СтатическиеДанные = Неопределено Тогда
СтатическиеДанные = ПолучитьПродажиЗаПериод(Месяц, Год);
КонецЕсли;
// Группируем продажи по менеджерам (O(n))
ПродажиПоМенеджерам = Новый Соответствие;
Для каждого СтрокаПродажи Из СтатическиеДанные Цикл
Ключ = СтрокаПродажи.Менеджер;
Если Не ПродажиПоМенеджерам.Получить(Ключ) Тогда
ПродажиПоМенеджерам.Вставить(Ключ, 0);
КонецЕсли;
ПродажиПоМенеджерам[Ключ] = ПродажиПоМенеджерам[Ключ] + СтрокаПродажи.Сумма;
КонецЦикла;
// Получаем настройки процентов (гибко)
Настройки = ПолучитьНастройкиВознаграждения(); // Например, из справочника
// Формируем результаты
ТаблицаРезультатов = Новый ТаблицаЗначений;
ТаблицаРезультатов.Колонки.Добавить("Менеджер");
ТаблицаРезультатов.Колонки.Добавить("Вознаграждение");
Для каждого Ключ, Сумма Из ПродажиПоМенеджерам Цикл
Менеджер = Справочники.Менеджеры.НайтиПоСсылке(Ключ);
Процент = РассчитатьПроцент(Сумма, Настройки); // Логика вынесена отдельно
Вознаграждение = Сумма * Процент;
НоваяСтрока = ТаблицаРезультатов.Добавить();
НоваяСтрока.Менеджер = Менеджер.Наименование;
НоваяСтрока.Вознаграждение = Вознаграждение;
КонецЦикла;
Возврат ТаблицаРезультатов;
КонецФункции
// Определяет процент по настройкам
Функция РассчитатьПроцент(Сумма, Настройки)
Для каждого СтрокаНастройки Из Настройки Цикл
Если Сумма >= СтрокаНастройки.Минимум Тогда
Возврат СтрокаНастройки.Процент;
КонецЕсли;
КонецЦикла;
Возврат 0.05; // Значение по умолчанию
КонецФункции
Пример 2. Более сложный пример рефакторинга логики
Псевдо-код записи нового пользователя ИБ
Промт-запросы в AI чате:
- Добавь комментарии к коду
- Сделай рефакторинг
Код до рефакторинга
Процедура ПередЗаписью(Отказ)
// Включаем привилегированный режим для операций с пользователями ИБ
УстановитьПривилегированныйРежим(Истина);
// Проверяем, является ли текущий пользователь или редактируемый объект администратором
ТекущийПользовательАдминистратор = ПараметрыСеанса.ТекущийПользователь = Справочники.Пользователи.Администратор;
ТекущийОбъектАдминистратор = Ссылка = Справочники.Пользователи.Администратор;
// Проверяем, что для пользователя выбрана хотя бы одна роль
РезультатПоиска = Роли.НайтиСтроки(Новый Структура("Выбрано", Истина));
Если РезультатПоиска.Количество() = 0 Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
// Для нового пользователя
Если ЭтоНовый() Тогда
// Проверяем, не существует ли уже пользователь с таким именем
ТекущийПользователь = ПользователиИнформационнойБазы.НайтиПоИмени(СокрЛП(Наименование));
Если ТекущийПользователь <> Неопределено Тогда
Отказ = Истина;
УстановитьПривилегированныйРежим(Ложь);
Возврат;
КонецЕсли;
// Создаем нового пользователя ИБ
ТекущийИдентификатор = ЗаписатьПользователяИБ();
Если ТекущийИдентификатор = Неопределено Тогда
Отказ = Истина;
УстановитьПривилегированныйРежим(Ложь);
Возврат;
КонецЕсли;
// Сохраняем идентификатор созданного пользователя
ИдентификаторПользователяИБ = ТекущийИдентификатор;
// Для существующего пользователя
Иначе
// Проверяем, существует ли пользователь ИБ
ТекущийПользователь = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(ИдентификаторПользователяИБ);
Если ТекущийПользователь <> Неопределено Тогда
Отказ = Истина;
УстановитьПривилегированныйРежим(Ложь);
Возврат;
КонецЕсли;
// Обновляем данные пользователя ИБ
ТекущийИдентификатор = ЗаписатьПользователяИБ();
Если ТекущийИдентификатор = Неопределено Тогда
Отказ = Истина;
УстановитьПривилегированныйРежим(Ложь);
Возврат;
КонецЕсли;
// Обновляем идентификатор пользователя
ИдентификаторПользователяИБ = ТекущийИдентификатор;
КонецЕсли;
// Очищаем табличную часть с ролями
Роли.Очистить();
// Отключаем привилегированный режим
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры
// Создает или обновляет пользователя информационной базы
//
// Возвращает:
// УникальныйИдентификатор - идентификатор созданного пользователя
// Неопределено - в случае ошибки
//
Функция ЗаписатьПользователяИБ()
Попытка
// Создаем нового пользователя ИБ
ПользовательИБ = ПользователиИнформационнойБазы.СоздатьПользователя();
// Заполняем основные свойства
ПользовательИБ.Имя = СокрЛП(Наименование);
ПользовательИБ.ПолноеИмя = СокрЛП(Наименование);
ПользовательИБ.АутентификацияОС = Ложь;
ПользовательИБ.АутентификацияOpenID = Ложь;
ПользовательИБ.АутентификацияСтандартная = Истина;
ПользовательИБ.ЗапрещеноИзменятьПароль = Ложь;
ПользовательИБ.ПоказыватьВСпискеВыбора = Истина;
ПользовательИБ.Пароль = "";
// Добавляем выбранные роли
Для Каждого Роль Из Роли Цикл
// Пропускаем невыбранные роли
Если Роль.Выбрано = Ложь Тогда
Продолжить;
КонецЕсли;
// Ищем метаданные роли
РезультатПоиска = Метаданные.Роли.Найти(Роль.Имя);
Если РезультатПоиска = Неопределено Тогда
Продолжить;
КонецЕсли;
// Добавляем роль пользователю
ПользовательИБ.Роли.Добавить(РезультатПоиска);
КонецЦикла;
// Сохраняем пользователя
ПользовательИБ.Записать();
// Возвращаем идентификатор созданного пользователя
Возврат ПользовательИБ.УникальныйИдентификатор;
Исключение
// В случае ошибки возвращаем Неопределено
Возврат Неопределено;
КонецПопытки;
КонецФункции;
Код после рефакторинга
Процедура ПередЗаписью(Отказ)
// Включаем привилегированный режим для выполнения административных операций
УстановитьПривилегированныйРежим(Истина);
// 1. Проверка наличия выбранных ролей
Если НЕ ПроверитьРоли(Отказ) Тогда
Возврат;
КонецЕсли;
// 2. Проверка и создание/обновление пользователя ИБ
Если НЕ ПроверитьИСоздатьПользователя(Отказ) Тогда
Возврат;
КонецЕсли;
// Очищаем табличную часть с ролями
Роли.Очистить();
// Отключаем привилегированный режим
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры
// Проверяет, что для пользователя выбрана хотя бы одна роль
//
// Параметры:
// Отказ - Флаг отказа в записи (выходной параметр)
//
// Возвращает:
// Булево - Истина, если проверка пройдена успешно
//
Функция ПроверитьРоли(Отказ) Экспорт
РезультатПоиска = Роли.НайтиСтроки(Новый Структура("Выбрано", Истина));
Если РезультатПоиска.Количество() = 0 Тогда
Отказ = Истина;
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
// Проверяет и создает/обновляет пользователя информационной базы
//
// Параметры:
// Отказ - Флаг отказа в записи (выходной параметр)
//
// Возвращает:
// Булево - Истина, если операция выполнена успешно
//
Функция ПроверитьИСоздатьПользователя(Отказ) Экспорт
// Получаем текущего пользователя (если существует)
ТекущийПользователь = ПолучитьТекущегоПользователя();
Если ТекущийПользователь <> Неопределено Тогда
Отказ = Истина;
УстановитьПривилегированныйРежим(Ложь);
Возврат Ложь;
КонецЕсли;
// Создаем/обновляем пользователя ИБ
ТекущийИдентификатор = ЗаписатьПользователяИБ();
Если ТекущийИдентификатор = Неопределено Тогда
Отказ = Истина;
УстановитьПривилегированныйРежим(Ложь);
Возврат Ложь;
КонецЕсли;
// Сохраняем идентификатор пользователя ИБ
ИдентификаторПользователяИБ = ТекущийИдентификатор;
Возврат Истина;
КонецФункции
// Получает пользователя информационной базы по данным справочника
//
// Возвращает:
// СправочникСсылка - Найденный пользователь или Неопределено
//
Функция ПолучитьТекущегоПользователя() Экспорт
Если ЭтоНовый() Тогда
// Для нового пользователя - поиск по имени
Возврат ПользователиИнформационнойБазы.НайтиПоИмени(СокрЛП(Наименование));
Иначе
// Для существующего - поиск по уникальному идентификатору
Возврат ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(ИдентификаторПользователяИБ);
КонецЕсли;
КонецФункции
// Создает или обновляет пользователя информационной базы
//
// Возвращает:
// УникальныйИдентификатор - Идентификатор созданного пользователя
// Неопределено - В случае ошибки
//
Функция ЗаписатьПользователяИБ() Экспорт
Попытка
// 1. Создание базового объекта пользователя
ПользовательИБ = СоздатьПользователяИБ();
// 2. Назначение ролей пользователю
НазначитьРолиПользователю(ПользовательИБ);
// 3. Сохранение пользователя
ПользовательИБ.Записать();
Возврат ПользовательИБ.УникальныйИдентификатор;
Исключение
// В случае ошибки возвращаем Неопределено
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Создает объект пользователя информационной базы с базовыми настройками
//
// Возвращает:
// ПользовательИнформационнойБазы - Созданный объект пользователя
//
Функция СоздатьПользователяИБ() Экспорт
ПользовательИБ = ПользователиИнформационнойБазы.СоздатьПользователя();
// Настройка основных параметров пользователя
ПользовательИБ.Имя = СокрЛП(Наименование);
ПользовательИБ.ПолноеИмя = СокрЛП(Наименование);
ПользовательИБ.АутентификацияОС = Ложь;
ПользовательИБ.АутентификацияOpenID = Ложь;
ПользовательИБ.АутентификацияСтандартная = Истина;
ПользовательИБ.ЗапрещеноИзменятьПароль = Ложь;
ПользовательИБ.ПоказыватьВСпискеВыбора = Истина;
ПользовательИБ.Пароль = "";
Возврат ПользовательИБ;
КонецФункции
// Назначает роли пользователю информационной базы
//
// Параметры:
// ПользовательИБ - Объект пользователя информационной базы
//
Процедура НазначитьРолиПользователю(ПользовательИБ) Экспорт
Для Каждого Роль Из Роли Цикл
// Пропускаем невыбранные роли
Если Роль.Выбрано = Ложь Тогда
Продолжить;
КонецЕсли;
// Ищем метаданные роли
РезультатПоиска = Метаданные.Роли.Найти(Роль.Имя);
Если РезультатПоиска = Неопределено Тогда
Продолжить;
КонецЕсли;
// Добавляем роль пользователю
ПользовательИБ.Роли.Добавить(РезультатПоиска);
КонецЦикла;
КонецПроцедуры
Итого по результатам
- бегло узнали возможности Cursor IDE
- взглянули на свой код со стороны
Идеи для автоматизации
- Использовать Cursor IDE для написания скриптов автоматизации тестирования, CI/CD
- Использование для анализа технологического журнала и других логов
- Поиск циклических зависимостей и т.п.
Выводы
- Cursor IDE не заменит 1С:Конфигуратор
- Поможет с ревью кода и автоматизацией рутинных операций
Спасибо за внимание!
Лайк, подписка, комментарий 😎