Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

Как перенести тему Sublime Text в Notepad++: пример Mariana

Windows

Оформление в Sublime Text и Notepad++ описывается принципиально по-разному, поэтому «скопировать цвета» из одной темы в другую нельзя. Sublime раскрашивает код по грамматикам TextMate — через области действия (scope) вида keyword.operator или entity.name.function.

Notepad++ работает на лексерах Scintilla, где у каждого элемента синтаксиса — жёстко заданный числовой идентификатор стиля. Ниже разобран перенос любой темы Sublime в Notepad++ на примере Mariana: перевод палитры, сборка глобальных цветов и перекраска всех языков одним скриптом вместо ручной правки двух тысяч строк.

Инструкция актуальна для веток Notepad++ 8.x.

Почему нельзя просто скопировать тему?

Файл темы Sublime (.sublime-color-scheme) — это набор правил, где каждое правило привязано к области действия. Одно правило "scope": "string" красит строки во всех языках сразу, потому что грамматика каждого языка сама сообщает редактору: «вот здесь строка». Раскраска семантическая и переносимая между языками.

В Notepad++ иначе. Лексер (SCLEX_PYTHON, SCLEX_CPP и десятки других) разбирает текст и присваивает каждому фрагменту числовой styleID. Строка в Python — это styleID=3, а в C++ — уже другой идентификатор внутри своего лексера.

Единого «стиля строки» на весь редактор нет: цвета задаются отдельно для каждого языка. Практический вывод — точного соответствия «одна тема Sublime → одна тема Notepad++» не существует. Результат достигается аппроксимацией: палитра оригинала раскладывается по стилям каждого лексера по смыслу.

Как устроена тема Notepad++?

Тема — это XML-файл с двумя секциями внутри корневого узла <NotepadPlus>:

  • <LexerStyles> — стили для каждого языка. Внутри — узлы <LexerType> (по одному на язык), а в них — <WordsStyle> для каждого элемента синтаксиса.
  • <GlobalStyles> — общие цвета редактора: фон, текст, каретка, выделение, номера строк, подсветка скобок, метки поиска.

У каждого стиля есть ключевые атрибуты: fgColor — цвет текста, bgColor — цвет фона, оба в формате RRGGBB без решётки.

Атрибут fontStyle — битовая маска начертания: 0 — обычный, 1 — полужирный, 2 — курсив, 4 — подчёркнутый. Комбинации складываются: например 3 — полужирный курсив.

Как перевести палитру из HSL в HEX?

Mariana задаёт цвета в HSL, а Notepad++ понимает только HEX. Перевод переменных темы выполняется небольшой функцией на Python — стандартной библиотеки достаточно.

import colorsys

def hsl_to_hex(h, s, l):
    r, g, b = colorsys.hls_to_rgb(h / 360, l / 100, s / 100)
    return "{:02X}{:02X}{:02X}".format(round(r * 255), round(g * 255), round(b * 255))

# blue3 из палитры Mariana — фон редактора
print(hsl_to_hex(210, 15, 22))   # -> 303841
# green — строки
print(hsl_to_hex(114, 31, 68))   # -> 99C794

Полная палитра Mariana после перевода:

ПеременнаяHEXРоль
blue3#303841фон редактора
white3#D8DEE9основной текст
blue6#A6ACB9комментарии
green#99C794строки
orange#F9AE58числа, параметры, каретка
pink#C695C6ключевые слова, типы
red2#F97B58операторы
blue#6699CCвызовы функций
blue5#5FB4B4имена функций, классы, ключи
red#EC5F66константы, теги
blue2 (на фоне)#4D5864выделение, текущая строка

Полупрозрачные цвета Mariana (например выделение hsla(210, 13%, 40%, 0.7)) в Notepad++ прозрачности не имеют. Их нужно предварительно наложить на цвет фона и получить непрозрачный HEX — иначе выделение будет выглядеть не так, как в оригинале.

Как собрать глобальные цвета?

Секция <GlobalStyles> отвечает за всё, что читатель видит в первую очередь: фон, текст, каретку, выделение. Это самая заметная часть темы, и её стоит выверить вручную.

Ниже — ключевые узлы для Mariana.

<GlobalStyles>
    <WidgetStyle name="Default Style" styleID="32" fgColor="D8DEE9" bgColor="303841" fontName="Consolas" fontStyle="0" fontSize="11" />
    <WidgetStyle name="Caret colour" styleID="0" fgColor="F9AE58" />
    <WidgetStyle name="Selected text colour" styleID="0" bgColor="4D5864" fgColor="D8DEE9" />
    <WidgetStyle name="Current line background colour" styleID="0" bgColor="4D5864" />
    <WidgetStyle name="Line number margin" styleID="33" fgColor="A6ACB9" bgColor="303841" fontName="" fontStyle="0" fontSize="" />
    <WidgetStyle name="Brace highlight style" styleID="34" fgColor="F9AE58" bgColor="303841" fontName="" fontStyle="1" fontSize="" />
    <WidgetStyle name="Find Mark Style" styleID="31" fgColor="333333" bgColor="FAC761" />
    <WidgetStyle name="Global override" styleID="0" fgColor="D8DEE9" bgColor="303841" fontName="" fontStyle="0" fontSize="" />
</GlobalStyles>

Имя стиля с styleID="0" менять нельзя — Notepad++ находит эти узлы по атрибуту name, а не по идентификатору. Названия вроде Caret colour или Current line background colour должны совпадать буква в букву.

Как перекрасить все языки разом?

Ручная правка стилей для каждого лексера — это тысячи строк. Путь короче: взять эталонный шаблон стилей из репозитория Notepad++ (stylers.model.xml — в нём уже перечислены все языки со всеми правильными styleID) и перекрасить каждый <WordsStyle> по смыслу его имени.

Имя стиля само подсказывает роль: COMMENT, STRING, NUMBER, KEYWORD, OPERATOR.

Сначала — таблица соответствия ролей и цветов Mariana. Это ядро переноса, применимое к любой теме:

Элемент кодаОбласть в SublimeЦвет
Комментарийcomment#A6ACB9
Строкаstring#99C794
Числоconstant.numeric#F9AE58
Ключевое словоkeyword#C695C6
Операторkeyword.operator#F97B58
Вызов функцииvariable.function#6699CC
Имя функции / классentity.name, support.class#5FB4B4
Тег / константаentity.name.tag, constant.language#EC5F66
Атрибутentity.other.attribute-name#C695C6
Текст по умолчаниюforeground#D8DEE9

Дальше — функция сопоставления. Она принимает имя стиля и возвращает цвет. Порядок проверок важен, о подводных камнях — сразу после кода.

def color_for(name):
    n = name.upper()
    # Нейтральные — проверяем первыми, чтобы не поймать по подстроке
    if "DEFAULT" in n or "IDENTIFIER" in n:   return "D8DEE9"  # текст
    if "COMMENT" in n:                         return "A6ACB9"  # комментарий
    if "INSTRUCTION" in n or "KEYWORD" in n:   return "C695C6"  # ключевое слово
    if "STRING" in n or "TRIPLE" in n:         return "99C794"  # строка
    if "NUMBER" in n:                          return "F9AE58"  # число
    if "OPERATOR" in n:                        return "F97B58"  # оператор
    if "TAG" in n or "CONSTANT" in n:          return "EC5F66"  # тег / константа
    if "ATTRIB" in n:                          return "C695C6"  # атрибут
    if "TYPE" in n or "CLASS" in n:            return "5FB4B4"  # тип / класс
    if "FUNCTION" in n or "DEF" in n:          return "6699CC"  # функция
    return "D8DEE9"

Проверка по подстроке коварна. «INSTRUCTION WORD» содержит «STRUCT» — если ветка типов стоит выше, ключевые слова окрасятся как классы. Аналогично «DEFAULT» содержит «DEF» и попадёт в ветку функций. Поэтому нейтральные имена и INSTRUCTION проверяются раньше, чем STRUCT, CLASS и DEF.

Дальше выполняется проход по всем <WordsStyle> в stylers.model.xml: fgColor подставляется из color_for(name), а bgColor у всех выставляется в фон 303841. Результат для лексера Python выглядит так:

<LexerType name="python" desc="Python" ext="">
    <WordsStyle name="DEFAULT"      styleID="0"  fgColor="D8DEE9" bgColor="303841" fontStyle="0" />
    <WordsStyle name="COMMENT LINE" styleID="1"  fgColor="A6ACB9" bgColor="303841" fontStyle="0" />
    <WordsStyle name="NUMBER"       styleID="2"  fgColor="F9AE58" bgColor="303841" fontStyle="0" />
    <WordsStyle name="STRING"       styleID="3"  fgColor="99C794" bgColor="303841" fontStyle="0" />
    <WordsStyle name="KEYWORDS"     styleID="5"  fgColor="C695C6" bgColor="303841" fontStyle="0" />
    <WordsStyle name="CLASS NAME"   styleID="8"  fgColor="5FB4B4" bgColor="303841" fontStyle="2" />
    <WordsStyle name="DEF NAME"     styleID="9"  fgColor="6699CC" bgColor="303841" fontStyle="0" />
    <WordsStyle name="OPERATOR"     styleID="10" fgColor="F97B58" bgColor="303841" fontStyle="0" />
</LexerType>

После генерации обязательно прогоните файл через любой валидатор XML — одна незакрытая кавычка, и Notepad++ молча откатится на тему по умолчанию, не сообщив об ошибке.

Как установить тему в Notepad++?

Перед установкой рекомендуется сохранить копию текущей темы из каталога themes — это запасной вариант на случай ошибки в новом файле.

Готовый файл темы устанавливается в три шага:

  • Скопировать Mariana.xml в каталог тем — вставить в адресную строку проводника путь %APPDATA%\Notepad++\themes\ и перенести файл туда.
  • Перезапустить Notepad++.
  • Открыть Настройки → Определение стилей, вверху в списке «Выбор темы» выбрать Mariana, нажать «Сохранить и закрыть».

Тема текста и тёмный режим самого интерфейса (меню, вкладки, панели) в Notepad++ управляются раздельно. Чтобы затемнить интерфейс, отдельно включите Настройки → Параметры → Тёмный режим.

Что не перенесётся из оригинала?

Аппроксимация упирается в возможности лексеров Scintilla, и о границах стоит знать заранее:

  • Точность областей. Sublime различает десятки подтипов внутри одной категории (например punctuation.definition.string.begin). Лексер Notepad++ таких тонкостей не выделяет — часть нюансов раскраски теряется.
  • f-строки Python. Выражения внутри {} в f-строке подсвечиваются как часть строки целиком, без отдельной раскраски вложенного кода.
  • Вызов против объявления. Notepad++ не везде отличает объявление функции от её вызова так, как это делает грамматика Sublime, поэтому оба могут получить один цвет.

Для повседневной работы это почти незаметно: фон, текст, комментарии, строки, ключевые слова и числа совпадают с оригиналом, а именно они формируют узнаваемый вид темы.

Эталонный шаблон стилей всех языков можно взять в официальном репозитории — notepad-plus-plus на GitHub.

Частые вопросы

Почему тему Sublime нельзя перенести один в один?

Sublime использует семантические области грамматик TextMate, единые для всех языков, а Notepad++ — числовые styleID отдельного лексера на каждый язык. Общего «стиля строки» на весь редактор нет, поэтому переносится палитра, а не сами правила.

Подойдёт ли метод для других тем, кроме Mariana?

Да. Таблица соответствия ролей и цветов и функция color_for универсальны — меняется только палитра на входе. Тот же скрипт перекрашивает эталонный шаблон под любую тему Sublime.

Где Notepad++ хранит темы?

Для установленной версии — в каталоге %APPDATA%\Notepad++\themes\. В переносной (portable) сборке темы лежат в подкаталоге themes внутри папки самого редактора.

После установки темы ничего не изменилось — в чём причина?

Чаще всего файл содержит ошибку XML, и Notepad++ молча вернулся к теме по умолчанию. Второй частый случай — тема не выбрана в списке «Выбор темы» в разделе Определение стилей. Проверка через валидатор XML устраняет первую причину.

Заключение

Перенос темы между Sublime Text и Notepad++ — это не копирование, а пересборка: семантические области грамматик TextMate раскладываются по числовым стилям лексеров Scintilla. Ключ к результату — таблица соответствия ролей и цветов плюс аккуратный порядок проверок в функции сопоставления, а автоматическая перекраска эталонного шаблона превращает многочасовую ручную правку в один прогон скрипта. Тот же приём работает для любой темы Sublime, а не только для Mariana — меняется лишь палитра на входе.

Оцените статью
ctrllife.ru
Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x