Оформление в Sublime Text и Notepad++ описывается принципиально по-разному, поэтому «скопировать цвета» из одной темы в другую нельзя. Sublime раскрашивает код по грамматикам TextMate — через области действия (scope) вида keyword.operator или entity.name.function.
Notepad++ работает на лексерах Scintilla, где у каждого элемента синтаксиса — жёстко заданный числовой идентификатор стиля. Ниже разобран перенос любой темы Sublime в Notepad++ на примере Mariana: перевод палитры, сборка глобальных цветов и перекраска всех языков одним скриптом вместо ручной правки двух тысяч строк.
Инструкция актуальна для веток Notepad++ 8.x.
- Почему нельзя просто скопировать тему?
- Как устроена тема Notepad++?
- Как перевести палитру из HSL в HEX?
- Как собрать глобальные цвета?
- Как перекрасить все языки разом?
- Как установить тему в Notepad++?
- Что не перенесётся из оригинала?
- Частые вопросы
- Почему тему Sublime нельзя перенести один в один?
- Подойдёт ли метод для других тем, кроме Mariana?
- Где Notepad++ хранит темы?
- После установки темы ничего не изменилось — в чём причина?
- Заключение
Почему нельзя просто скопировать тему?
Файл темы 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 — меняется лишь палитра на входе.









