Минималистический редактор кода для поля HTML документа на Webkit 605

14.05.26

Разработка - Инструментарий разработчика

Минималистичный редактор кода с поддержкой подсветки кода, который не требует внешних зависимостей, сохранения макетов и прочего.

Файлы

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование Скачано Купить файл
Минималистический редактор кода для поля HTML документа на Webkit 605
.epf 14,13Kb
1 2 500 руб. Купить

Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний

Оформите подписку на компанию для решения рабочих задач

Оформить подписку и скачать решение со скидкой

Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

История вопроса - в обычных формах была возможность вывести редактор кода, после перехода на управляемые формы механику убрали.

Из того, что осталось:

1. Простое поле ввода - нет подсветки кода

2. Поле форматированного документа - подсветку можно добавить отдельно, но в реальном времени подсветка кода не отображается

3. Внешние редакторы кода

  - monaco editor (вариант VS code) - известный проект https://github.com/salexdv/bsl_console. Из проблем - нужно либо сохранять файлы в папку, либо указывать ссылку https://salexdv.github.io/bsl_console/src/index.html. Сама по себе функциональная и много где используется, но тяжёлая и нестабильная.

  - ace editor

  - codemirror

Хотелось чего-то простого и лёгкого. При этом важно, что в платформе старая версия Webkit 605 https://habr.com/ru/companies/1c/articles/425713/

Исходя из этого с помощью нейросетей собрал простой редактор кода.

 

Функционал:

1. Подсветка кода (алгоритм раскраски на базе 1С также есть в статье)

2. Номера строк (немного расходятся при прокрутке до самого низа, но не особо критично - решил оставить как есть)

3. Возможность прикрутить синтаксис подсказку через 1С. Базовый пример есть в 1С, остальное можно реализовать самостоятельно. Например анализ метаданных, чтобы подтягивались общие модули, справочники, документы.

4. Мелкие штрихи - работа с табуляцией

Как интегрировать - скопировать код и подключить его в обработчике "ПриСозданииНаСервере". Все элементы формы и команды для синтаксис подсказки создаются программно.

Для ленивых положил файл обработки за 1$CM

 

Код редактора

 

#Область ОбработчикиСобытийФормы
	
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	// Обязательная часть
	НачальныйКод =
		"Сообщить (""Установка кода при открытии формы"");
		|#Область Пример
		|// Комментарии
		|Функция МойПример() 
		|	Дата = '2026-05-14';
		|	Строка = ""Пример строки"";
		|	Число = 12345.678;
		|КонецФункции
		|#КонецОбласти";
	ИнициализацияРедактора(НачальныйКод);
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область РедакторКодаВHML
	
// Обязательная часть
&НаСервере
Процедура ИнициализацияРедактора(НачальныйКод = "")

	// Сам редактор - обязательно
	ДобавляемыеРеквизиты = Новый Массив;
	ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("Редактор", Новый ОписаниеТипов("Строка")));
	ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("НачальныйКод", Новый ОписаниеТипов("Строка")));
	ИзменитьРеквизиты(ДобавляемыеРеквизиты);
	//ЭтотОбъект.Редактор = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Редактор").ПолучитьТекст();
	ЭтотОбъект.Редактор = МакетРедактора();
	ЭтотОбъект.НачальныйКод = НачальныйКод;
	
	ЭлементФормы = Элементы.Добавить("Редактор", Тип("ПолеФормы"));
	ЭлементФормы.Вид = ВидПоляФормы.ПолеHTMLДокумента;
	ЭлементФормы.ПутьКДанным = "Редактор";
	ЭлементФормы.УстановитьДействие("ДокументСформирован", "РедакторДокументСформирован");

	// Команда контекстной подсказки - необязательно
	Команда = ЭтаФорма.Команды.Добавить("Подсказка");
	Команда.Действие = "Подсказка";
	Команда.СочетаниеКлавиш = Новый СочетаниеКлавиш(Клавиша.Space,, Истина);
	
	Кнопка = ЭтаФорма.Элементы.Добавить("КнопкаПодсказка", Тип("КнопкаФормы"), Элементы.РедакторКонтекстноеМеню);
	Кнопка.ИмяКоманды = "Подсказка";

КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Функция МакетРедактора()

	Возврат
	
"<DOCTYPE html>
|<html>
|<head>
|  <meta charset='UTF-8'>
|  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
|  <style>
|    html,
|    body {
|      margin: 0;
|      padding: 0;
|      height: 100%;
|      overflow: hidden;
|    }
|
|    .editor {
|      position: absolute;
|      top: 0;
|      left: 0;
|      width: 100%;
|      height: 100%;
|      overflow: hidden;
|      background: #fff;
|    }
|
|    #lines {
|      position: absolute;
|      top: 0;
|      left: 0;
|      width: 40px;
|      height: 100%;
|      padding-top: 8px;
|      padding-bottom: 8px;
|      background: #f5f5f5;
|      border-right: 1px solid #ddd;
|      overflow: hidden;
|      pointer-events: none;
|      z-index: 3;
|      font: 14px/1.5 Consolas, Monaco, monospace;
|      color: #888;
|      text-align: right;
|      box-sizing: border-box;
|    }
|
|    #lines div {
|      margin: 0;
|      padding: 0;
|      line-height: 1.5;
|    }
|
|    #hl,
|    #code {
|      position: absolute;
|      top: 0;
|      left: 0;
|      width: 100%;
|      height: 100%;
|      margin: 0;
|      padding: 8px 8px 8px 48px;
|      font: 14px/1.5 Consolas, Monaco, monospace;
|      overflow: auto;
|      white-space: pre;
|      box-sizing: border-box;
|      tab-size: 4;
|    }
|
|    textarea {
|      background: transparent;
|      color: rgba(0, 0, 0, 0.01);
|      z-index: 2;
|      resize: none;
|      border: 0;
|      outline: 0;
|      caret-color: #000;
|    }
|
|    pre {
|      z-index: 1;
|      pointer-events: none;
|      color: #333;
|    }
|
|    /* 1С ключевые слова */
|    .keyword {
|      color: #f00;
|      font-weight: bold;
|    }
|
|    .identifier {
|      color: #00f;
|    }
|
|    /* Комментарии */
|    .comment {
|      color: #008000;
|    }
|
|    /* Препроцессор */
|    .preproc {
|      color: #963200;
|    }
|
|    /* Аннотации */
|    .annotation {
|      color: #963200;
|    }
|
|    /* Числа */
|    .number {
|      color: #000;
|    }
|
|    /* Строки */
|    .string {
|      color: #aaa;
|    }
|
|    /* Даты */
|    .date {
|      color: #000;
|    }
|
|    .operator {
|      color: #f00;
|    }
|
|    .error {
|      color: #f80;
|    }
|
|    /* Директивы препроцессора */
|    .dir {
|      color: #800080;
|    }
|
|  </style>
|</head>
|
|<body>
|
|  <div class='editor'>
|    <div id='lines'></div>
|    <pre id='hl'></pre>
|    <textarea id='code' spellcheck='false' autocomplete='off' wrap='off'
|      placeholder='Начните вводить код...'></textarea>
|  </div>
|
|  <script>
|    var ta = document.getElementById('code');
|    var hl = document.getElementById('hl');
|    var lines = document.getElementById('lines');
|    const keywords = 'если if тогда then иначеесли elsif иначе else конецесли endif для for каждого each из in по to пока while цикл do конеццикла enddo ждать await процедура procedure функция function конецпроцедуры endprocedure конецфункции endfunction перем var перейти goto возврат return продолжить continue прервать break и and или or не not попытка try исключение except вызватьисключение raise конецпопытки endtry новый new выполнить execute асинх истина ложь null Неопределено'.split(' ')
|
|    function endLexemExecute(element, props, endLexem) {
|      const lexem = element.slice(props.beginLexem, endLexem)
|      var type = props.lexemType
|      var result
|      if (type == 'identifier' && keywords.includes(lexem.toLowerCase())) {
|        type = 'keyword'
|      } else if (type == 'numberWithDot') {
|        type = 'number'
|      }
|
|      props.beginLexem = endLexem
|      if (type == undefined || lexem.length == 0) {
|        result = lexem
|      } else {
|        result = '<span class=""' + type + '"">' + lexem + '</span>'
|      }
|      props.lexemType = undefined
|      return result
|    }
|
|    function highlightCode(code) {
|
|      var result = [];
|      var props = {
|        lexemType: undefined,
|        beginLexem: 0
|      }
|
|      // Сначала экранируем HTML
|      code = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
|      
|      code.split('\n').forEach((element, index) => {
|        let i = 0
|        props.beginLexem = 0
|        while (i < element.length) {
|          let symbol = element[i]
|          let symbolNext = element[i + 1]
|          if (props.lexemType == undefined) {
|            if (symbol == '/' && symbolNext == '/') {
|              props.lexemType = 'comment'
|              result.push(endLexemExecute(element, props, element.length))
|              break
|            } else if (symbol == '#') {
|              props.lexemType = 'preproc'
|              result.push(endLexemExecute(element, props, element.length))
|              break
|            } else if (symbol == '&') {
|              props.lexemType = 'annotation'
|              result.push(endLexemExecute(element, props, element.length))
|              break
|            } else if (symbol == '""' || symbol == '|') {
|              props.lexemType = 'string'
|            } else if (symbol == ""'"") {
|              props.lexemType = 'date'
|            } else if ('абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz_'.includes(symbol.toLowerCase())) {
|              props.lexemType = 'identifier'
|            } else if ('0123456789'.includes(symbol)) {
|              props.lexemType = 'number'
|            } else if (' \t'.includes(symbol)) {
|              props.lexemType = 'whitespace'
|            } else if ('()[]+-*/%<>=~;:.,'.includes(symbol)) {
|              props.lexemType = 'operator'
|              result.push(endLexemExecute(element, props, i + 1))
|            } else {
|              props.lexemType = 'error'
|              result.push(endLexemExecute(element, props, i + 1))
|            }
|          } else if (props.lexemType == 'string' && symbol == '""') {
|            if (symbolNext == '""') {
|              i++
|            } else {
|              result.push(endLexemExecute(element, props, i + 1))
|            }
|          } else if (props.lexemType == 'date' && symbol == ""'"") {
|            result.push(endLexemExecute(element, props, i + 1))
|          } else if (props.lexemType == 'identifier'
|            && ! 'абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz_0123456789'.includes(symbol.toLowerCase())) {
|            result.push(endLexemExecute(element, props, i))
|            continue
|          } else if (props.lexemType == 'number') {
|            if (symbol == '.') {
|              props.lexemType = 'numberWithDot'
|            } else if (! '0123456789'.includes(symbol)) {
|              result.push(endLexemExecute(element, props, i))
|              continue
|            }
|          } else if (props.lexemType == 'numberWithDot' && ! '0123456789'.includes(symbol)) {
|            result.push(endLexemExecute(element, props, i))
|            continue
|          } else if (props.lexemType == 'whitespace' && !(' \t'.includes(symbol))) {
|            result.push(endLexemExecute(element, props, i))
|            continue
|          }
|          i++
|        }
|        result.push(endLexemExecute(element, props, i))
|        result.push('\n')
|      });
|      return result.join('');
|    }
|
|    function render() {
|      var v = ta.value;
|      hl.innerHTML = highlightCode(v);
|
|      var lineCount = v.split('\n').length;
|      var html = '';
|      for (var i = 1; i <= lineCount; i++) {
|        html += '<div>' + i + '</div>';
|      }
|      lines.innerHTML = html;
|    }
|
|    function syncscroll() {
|      hl.scrollTop = ta.scrollTop;
|      hl.scrollLeft = ta.scrollLeft;
|      lines.scrollTop = ta.scrollTop;
|    }
|    document.render = render
|
|    ta.addEventListener('input', function () {
|      render();
|      syncscroll();
|    });
|
|    ta.addEventListener('scroll', syncscroll);
|
|    ta.addEventListener('keydown', function (e) {
|      // Tab
|      if (e.keyCode === 9) {
|        e.preventDefault();
|        var start = ta.selectionStart;
|        var end = ta.selectionEnd;
|        
|        // Если есть выделение
|        if (start !== end) {
|          var selectedText = ta.value.substring(start, end);
|          var lines = selectedText.split('\n');
|          
|          if (e.shiftKey) {
|            // Shift+Tab: убираем отступ
|            lines = lines.map(function(line) {
|              if (line.startsWith('\t')) {
|                return line.substring(1);
|              }
|              // Также убираем пробельные отступы (4 пробела)
|              var spacesToRemove = 0;
|              for (var i = 0; i < line.length && i < 4; i++) {
|                if (line[i] === ' ') {
|                  spacesToRemove++;
|                } else {
|                  break;
|                }
|              }
|              return line.substring(spacesToRemove);
|            });
|          } else {
|            // Tab: добавляем отступ
|            lines = lines.map(function(line) {
|              return '\t' + line;
|            });
|          }
|          
|          var newSelectedText = lines.join('\n');
|          ta.value = ta.value.substring(0, start) + newSelectedText + ta.value.substring(end);
|          
|          // Восстанавливаем выделение с учётом изменений
|          var lengthDiff = newSelectedText.length - selectedText.length;
|          ta.selectionStart = start;
|          ta.selectionEnd = end + lengthDiff;
|        } else {
|          // Нет выделения: просто вставляем табуляцию
|          document.execCommand('insertText', false, '\t')
|        }
|        
|        render();
|      }
|
|      // Enter - автоотступ
|      if (e.keyCode === 13) {
|        e.preventDefault();
|        var start = ta.selectionStart;
|        var end = ta.selectionEnd;
|        
|        // Находим предыдущую строку
|        var textBeforeCursor = ta.value.substring(0, start);
|        var lastNewlineIndex = textBeforeCursor.lastIndexOf('\n');
|        var previousLine = lastNewlineIndex >= 0 
|          ? textBeforeCursor.substring(lastNewlineIndex + 1, start)
|          : textBeforeCursor;
|        
|        // Подсчитываем количество ведущих табуляций
|        var indent = '';
|        for (var i = 0; i < previousLine.length; i++) {
|          if (previousLine[i] === '\t') {
|            indent += '\t';
|          } else {
|            break;
|          }
|        }
|        
|        // Вставляем перенос строки и отступ через execCommand для сохранения истории
|        document.execCommand('insertText', false, '\n' + indent);
|        
|        render();
|      }
|
|
|    });
|
|    // Инициализация
|    render();
|  </script>
|</body>
|
|</html>"

КонецФункции

&НаКлиенте
Процедура УстановитьКодВРедактор(КодДляУстановки)

	ОбластьРедактора().value = КодДляУстановки;
	Документ().render();

КонецПроцедуры

&НаКлиенте
Процедура РедакторДокументСформирован(Элемент)
	УстановитьКодВРедактор(ЭтотОбъект.НачальныйКод);
КонецПроцедуры

// Контекстная подсказка - необязательная часть
&НаКлиенте
Асинх Процедура Подсказка(Команда)
	
	КлючевыеСлова = СтрРазделить("Если Тогда ИначеЕсли Иначе КонецЕсли Для Каждого Из По Пока Цикл КонецЦикла Ждать Процедура Функция КонецПроцедуры КонецФункции Перем Перейти Возврат Продолжить Прервать И Или Не Попытка Исключение ВызватьИсключение КонецПопытки Новый Выполнить Асинх Истина Ложь Null Неопределено", " ");
	
	ТекущийТекст = РедакторТекст();
	ПозицияКурсора = РедакторНачалоВыделения();
	НачалоСтроки = ПозицияКурсора;
	Буфер = "";
	
	Пока ПозицияКурсора > 0 Цикл
		Символ = НРег(Сред(ТекущийТекст, ПозицияКурсора, 1));
		Если СтрНайти("абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz_", Символ) = 0 Тогда
			Прервать;
		КонецЕсли;
		Буфер = Символ + Буфер;
		ПозицияКурсора = ПозицияКурсора - 1;
	КонецЦикла;
	
	Если СтрДлина(Буфер) = 0 Тогда
		Возврат
	КонецЕсли;
	
	Варианты = Новый СписокЗначений;
	
	Для каждого КлючевоеСлово Из КлючевыеСлова Цикл
		
		Если СтрНачинаетсяС(НРег(КлючевоеСлово), Буфер) Тогда
			Варианты.Добавить(КлючевоеСлово);
		КонецЕсли;
		
	КонецЦикла;
	
	Если Не Варианты.Количество() Тогда
		Возврат;
	ИначеЕсли Варианты.Количество() = 1 Тогда
		ВыбранныйВариант = Варианты[0];
	Иначе
		ВыбранныйВариант = Ждать ВыбратьИзСпискаАсинх(Варианты);
	КонецЕсли;
	
	Если ВыбранныйВариант = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Документ().execCommand("insertText", false, Сред(ВыбранныйВариант.Значение, СтрДлина(Буфер) + 1));
	
КонецПроцедуры

&НаКлиенте
Функция Документ()

	Возврат Элементы.Редактор.Документ;

КонецФункции

&НаКлиенте
Функция ОбластьРедактора()

	Возврат Документ().getElementById("code");

КонецФункции

&НаКлиенте
Функция РедакторТекст()

	Возврат ОбластьРедактора().value;

КонецФункции

&НаКлиенте
Функция РедакторНачалоВыделения()

	Возврат ОбластьРедактора().selectionStart;

КонецФункции


#КонецОбласти

#КонецОбласти

 

Проект редактора на базе JavaScript - https://github.com/fotov/bsl_html_code_editor

 

Дополнительно - код раскраски на базе 1С

 

#Область ОбработчикиСобытийФормы
	
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	Код = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет").ПолучитьТекст();
	РаскраситьКод(Код);
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

&НаСервере
Процедура РаскраситьКод(Код)

	Параграфы = ВыделитьЛексемы(Код);

	Цвета = Новый Соответствие;
	Цвета.Вставить("АННОТАЦИИ", 	Новый Цвет(150, 50, 0));
	Цвета.Вставить("ПРЕПРОЦЕССОР",	Новый Цвет(150, 50, 0));
	Цвета.Вставить("КОММЕНТАРИЙ",	WebЦвета.Зеленый);
	//Цвета.Вставить("СТРОКА",		WebЦвета.Черный);
	//Цвета.Вставить("ДАТА",		WebЦвета.Черный);
	//Цвета.Вставить("ЧИСЛО",		WebЦвета.Черный);
	Цвета.Вставить("ОШИБКА",		WebЦвета.Розовый);
	Цвета.Вставить("ИДЕНТИФИКАТОР",	WebЦвета.Синий);
	Цвета.Вставить("КЛЮЧЕВОЕСЛОВО",	WebЦвета.Красный);
	Цвета.Вставить("ОПЕРАТОР", 		WebЦвета.Красный);
	
	Для каждого Параграф Из Параграфы Цикл
	
		Для каждого Лексема Из Параграф Цикл
			Текст = ФД.Добавить(Лексема.Значение);
			//Текст.Шрифт = Новый Шрифт("Consolas");
			Если Цвета[Лексема.Тип] <> Неопределено Тогда
				Текст.ЦветТекста = Цвета[Лексема.Тип];
			КонецЕсли;
		КонецЦикла;
		
		ФД.Добавить(, Тип("ПереводСтрокиФорматированногоДокумента"));
	
	КонецЦикла;

КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Функция ВыделитьЛексемы(Знач Код)
	
	Параграфы = Новый Массив;
	
	Для каждого Строка Из СтрРазделить(Код, Символы.ПС) Цикл
		
		Лексемы = Новый Массив;
		Состояние = Неопределено;
		ДлинаСтроки = СтрДлина(Строка);
		н = 1;
		НачалоЛексемы = 1;
		Пока н <= ДлинаСтроки Цикл
			
			Символ = Сред(Строка, н, 1);
			СледующийСимвол = Сред(Строка, н + 1, 1);
			Если Состояние = Неопределено Тогда
			
				Если Символ = "/" И СледующийСимвол = "/" Тогда
					ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, ДлинаСтроки, "КОММЕНТАРИЙ");
					Прервать;
				ИначеЕсли Символ = "#" Тогда
					ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, ДлинаСтроки, "ПРЕПРОЦЕССОР");
					Прервать;
				ИначеЕсли Символ = "&" Тогда
					ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, ДлинаСтроки, "АННОТАЦИИ");
					Прервать;
				ИначеЕсли Символ = """" Или Символ = "|" Тогда
					Состояние = "СТРОКА";
				ИначеЕсли Символ = "'" Тогда
					Состояние = "ДАТА";
				ИначеЕсли СтрНайти("абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz_", НРег(Символ)) > 0 Тогда
					Состояние = "ИДЕНТИФИКАТОР";
				ИначеЕсли СтрНайти("0123456789", Символ) > 0 Тогда
					Состояние = "ЧИСЛО";
				ИначеЕсли СтрНайти(" 	", Символ) > 0 Тогда
					Состояние = "ПРОБЕЛЬНЫЕСИМВОЛЫ";
				ИначеЕсли СтрНайти("()[]+-*/%<>=~;:.,'", Символ) > 0 Тогда
					Состояние = "ОПЕРАТОР";
					ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н, Состояние);
				Иначе
					Состояние = "ОШИБКА";
				КонецЕсли;
				
			ИначеЕсли Состояние = "СТРОКА" И Символ = """" Тогда
				Если СледующийСимвол = """" Тогда
					н = н + 1;
				Иначе
					ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н, Состояние);
				КонецЕсли;
			ИначеЕсли Состояние = "ДАТА" И Символ = "'"Тогда
				ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н, Состояние);
			ИначеЕсли Состояние = "ИДЕНТИФИКАТОР"
				И СтрНайти("абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz_0123456789", НРег(Символ)) = 0 Тогда
				ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н - 1, Состояние);
				Продолжить;
			ИначеЕсли Состояние = "ЧИСЛО" Тогда 
				Если Символ = "." Тогда
					Состояние = "ЧИСЛОСДРОБНОЙЧАСТЬЮ";
				ИначеЕсли СтрНайти("0123456789", Символ) = 0 Тогда 
					ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н - 1, Состояние);
					Продолжить;
				КонецЕсли;
			ИначеЕсли Состояние = "ЧИСЛОСДРОБНОЙЧАСТЬЮ" И СтрНайти("0123456789", Символ) = 0 Тогда
				ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н - 1, Состояние);
				Продолжить;
			ИначеЕсли Состояние = "ПРОБЕЛЬНЫЕСИМВОЛЫ" И СтрНайти(" 	", Символ) = 0 Тогда
				ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н - 1, Состояние);
				Продолжить;
			КонецЕсли;
			
			н = н + 1;
			
		КонецЦикла;
		
		ЗавершитьОбработкуЛексемы(Лексемы, Строка, НачалоЛексемы, н, Состояние);
		
		Параграфы.Добавить(Лексемы);
		
	КонецЦикла;
	Возврат Параграфы;

КонецФункции

&НаКлиентеНаСервереБезКонтекста
Процедура ЗавершитьОбработкуЛексемы(Лексемы, Строка, Начало, Конец, Состояние)

	Лексема = Сред(Строка, Начало, Конец - Начало + 1);
	
	Если Состояние = "ИДЕНТИФИКАТОР"
		И СтрНайти(" если if тогда then иначеесли elsif иначе else конецесли endif для for каждого each из in по to пока while цикл do конеццикла enddo ждать await процедура procedure функция function конецпроцедуры endprocedure конецфункции endfunction перем var перейти goto возврат return продолжить continue прервать break и and или or не not попытка try исключение except вызватьисключение raise конецпопытки endtry новый new выполнить execute асинх истина ложь null неопределено "
			, СтрШаблон(" %1 ", НРег(Лексема))) > 0 Тогда
		Тип = "КЛЮЧЕВОЕСЛОВО";
	Иначе
		Тип = Состояние;
	КонецЕсли;
	
	Если Лексема <> "" Тогда
		Лексемы.Добавить(Новый Структура("Тип, Значение", Тип, Лексема));
	КонецЕсли;
	
	Состояние = Неопределено;
	Начало = Конец + 1;

КонецПроцедуры

#КонецОбласти

upd - добавил программную установку кода

Проверено на следующих конфигурациях и релизах:

  • 1С:Библиотека стандартных подсистем, редакция 3.1, релизы 3.1.11.366

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 руб.

02.09.2020    258440    1428    421    

1165

Инструментарий разработчика Чистка данных Свертка базы Инструменты администратора БД Системный администратор Программист Руководитель проекта 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Платные (руб)

Инструмент представляет собой обработку для проведения свёртки или обрезки баз данных. Работает на ЛЮБЫХ конфигурациях (УТ, БП, ERP, УНФ, КА и т.д.). Поддерживаются серверные и файловые базы, управляемые и обычные формы. Может выполнять свертку одновременно в несколько потоков. А так же автоматически, без непосредственного участия пользователя. Решение в Реестре отечественного ПО

24900 руб.

20.08.2024    67809    356    164    

312

Инструментарий разработчика Нейросети Платные (руб)

Первые попытки разработки на 1С с использованием больших языковых моделей (LLM) могут разочаровать. LLMки сильно галлюцинируют, потому что не знают устройства конфигураций 1С, не знают нюансов синтаксиса. Но если дать им подсказки с помощью MCP, то результат получается кардинально лучше. Далее в публикации: MCP для поиска по метаданным 1С, справке синтакс-помощника и проверки синтаксиса.

15250 руб.

25.08.2025    54663    111    29    

123

Пакетная печать Печатные формы Инструментарий разработчика Программист 1С:Предприятие 8 Платные (руб)

Расширение для создания и редактирования печатных форм в системе 1С:Предприятие 8.3. Благодаря конструктору можно значительно снизить затраты времени на разработку печатных форм, повысить качество и прозрачность разработки, а также навести порядок в многообразии корпоративных печатных форм. Обновление версии от 21.04.26

22570 руб.

06.10.2023    38141    101    46    

122

Работа с интерфейсом Анализ учета Мониторинг 1С:Предприятие 8 1С 8.3 1C:Бухгалтерия 1С:Бухгалтерия 3.0 1С:ERP Управление предприятием 2 1С:Управление холдингом 1С:Зарплата и Управление Персоналом 3.x 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Управление торговлей 11 Платные (руб)

Создайте свой функциональный интерфейс в любой конфигурации 1С с помощью расширения Infostart Dashboard. Настраивайте панели виджетов с метриками, индикаторами и показателями на начальном экране. Узнайте возможность внедрения подсистемы у себя в конфигурации с помощью бесплатной обработки "Анализ внедрения подсистемы 1С Infostart Dashboard"!

31720 руб.

27.03.2025    83821    59    42    

70

Инструменты администратора БД Инструментарий разработчика Роли и права Программист 1С:Предприятие 8 1C:Бухгалтерия Россия Платные (руб)

Расширение позволяет без изменения кода конфигурации выполнять проверки при вводе данных, скрывать от пользователя недоступные ему данные, выполнять код в обработчиках. Не изменяет данные конфигурации, легко устанавливается практически на любую конфигурацию на управляемых формах.

17000 руб.

10.11.2023    25213    93    46    

102

Мастера заполнения Поиск данных Инструментарий разработчика Подбор и обработка объектов 1С 8.3 1С 8.5 Платные (руб)

Infostart MagicInput улучшает подбор в полях ввода 1С: ищет по любой части названия и по нескольким ключевым фрагментам, распознаёт ввод в другой раскладке и показывает иконки/статусы объектов прямо в списке. Поддерживает вставку навигационной ссылки/представления документа для автоподбора; для разработчиков доступны поиск по GUID и полному имени предопределённого. Работает в управляемых формах и подключается в большинстве конфигураций 1С 8.3/8.5.

6000 руб.

25.02.2026    3588    13    1    

16

Инструментарий разработчика Программист 1С:Предприятие 8 Платные (руб)

Инструмент для написания и отладки кода в режиме «1С:Предприятие». Представляет собой консоль кода с возможностью пошаговой отладки, просмотра значений переменных любых типов, использования процедур и функций, просмотра стека вызовов, вычисления произвольных выражений на встроенном языке в контексте точки останова, синтаксического контроля и остановки по ошибке. В консоли используется удобный редактор кода с подсветкой, контекстной подсказкой, возможностью вызова конструкторов запроса и форматной строки. 1.3.11 Доработан механизм контекстной подсказки по метаданным

9500 руб.

17.05.2024    52825    182    63    

216
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. n_mezentsev 139 14.05.26 11:00 Сейчас в теме
Странно, вы сделали редактор с претензией на роль встроенного, но не показали кода установки текста для редактирования, всегда начинать с "Начните вводить код..."?
YA_1454059215; +1 Ответить
5. fotov 340 14.05.26 17:42 Сейчас в теме
(1) добавил программную установку кода УстановитьКодВРедактор(КодДляУстановки)

из особенностей - установка кода работает только после выполнения кода редактора - должно сработать событие "ДокументСформирован"

поэтому если нужно устанавливать код при открытии - создаётся дополнительный реквизит, куда помещается код, который будет установлен после события ДокументСформирован
n_mezentsev; +1 Ответить
2. RustIG 1954 14.05.26 12:41 Сейчас в теме
картинок не хватает
3. fotov 340 14.05.26 14:09 Сейчас в теме
(2) в редакторе кода, или картинок интерфейса?
4. YA_1454059215 6 14.05.26 15:26 Сейчас в теме
(3) Картинок интерфейса
6. starik-2005 3272 14.05.26 18:27 Сейчас в теме
Хотелось чего-то простого и лёгкого. При этом важно, что в платформе старая версия Webkit 605 https://habr.com/ru/companies/1c/articles/425713/
Имха, они с 18-го года уже несколько раз вебкит обновили.
https://infostart.ru/1c/articles/2411240/
7. fotov 340 15.05.26 00:25 Сейчас в теме
(6) запустил скрипт по проверке версии WebKit на последней 8.3.27

в списке изменений версий - webkit обновлялся только для версий с Linux ((

Браузер: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1 (KHTML, like Gecko) V8WebKit

Полный User Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1 (KHTML, like Gecko) V8WebKit
8. starik-2005 3272 15.05.26 08:12 Сейчас в теме
(7)
Linux
В линухе вообще можно либы снести в каталоге - будут использоваться системные, если установлены:
/opt/1cv8/x86_64/8.3.27.1936/webkit2_extu-3.0.so
/opt/1cv8/x86_64/8.3.27.1936/webkit2_extu-3.0.so.wk41
/opt/1cv8/x86_64/8.3.27.1936/webkit2ext
/opt/1cv8/x86_64/8.3.27.1936/webkit2ext/webkit2_extu-3.0.so
Пишут, что в 8.5.4 обновят и для вендузятников.
Для отправки сообщения требуется регистрация/авторизация