Подсветка кода Python в стиле idleclassic для html-файлов

Описание

При публикации учебных примеров по программированию в Интернет целесообразно делать подсветку кода. Это улучшает восприятие текста, делает его красивее. Стандартный вариант подсветки кода для Python - это библиотека Pygments. Она по умолчанию присутствует в дистрибутиве Anaconda 2, так что устанавливать ее не требуется.

Для подсветки кода Python пакет Pygments предлагает на выбор целый набор цветовых схем - стилей. К сожалению, среди них нет самой привычной схемы - принятой в стандартном редакторе Idle. Поэтому ее нужно устанавливать отдельно.

Установка стиля idleclassic

Для начала придется установить свободную систему управления версиями Git, созданную в свое время Линусом Торвальдсом для работы над ядром Linux. Это неизбежно, потому что пакет pygments-style-idleclassic лежит на Github.com и закачивать его нужно через Git. Проверить корректность установки Git можно, набрав в командной строке Windows команду:

$ git

В окне командной строки должна появиться справка о командах git. Теперь можно приступать к установке стиля idleclassic. Клонируем репозиторий стиля в новый каталог pygments-style-idleclassic на вашем компьютере:

$ git clone git://github.com/zankophi/pygments-style-idleclassic.git

Переходим в этот каталог, набирая в командной строке команду:

$ cd pygments-style-idleclassic

Наконец, устанавливаем стиль idleclassic с помощью команды:

$ python setup.py install

Для нее могут потребоваться права администратора. Если система не видит интерпретатор python, нужно прописать каталог, в котором находится файл python.exe (например, C:\ProgramData\Anaconda2\), в системной переменной среды path.

Пример

Если нужно подсветить только одну строчку кода, можно воспользоваться шаблоном:

from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter

code ="from Tkinter import *"
print highlight(code,PythonLexer(),HtmlFormatter(noclasses=True,style='idleclassic',cssstyles='border: 1px solid grey;padding: 3px'))

В переменную code записывается код Python, который нужно подсветить. В результате выполнения приведенного выше сценария в окне командной строки интерпретатора Python появится код html, который можно вставить в вашу интернет-страничку:

Если требуется "раскрасить" целую программу или значительный ее фрагмент, нужно записать ее в файл, скажем x.py, и выполнить в командной строке Windows команду:

$ pygmentize -f html -O style=idleclassic -P cssstyles="border: 1px solid grey;padding: 3px" -P noclasses=True -o x.html x.py

В итоге в файле x.html будет записан "разноцветный" код Python (в формате html), который можно сразу вставлять в ваш html-файл.

Опция cssstyles в обоих примерах отвечает за отрисовку обрамляющей рамки серого цвета толщиной 1 пиксель и устанавливает величину зазора между рамкой и текстом внутри ее (3px). Именно так оформлена вставка кода Python в настоящем тексте.

Разумеется, приведенные выше рецепты будут работать не только для стиля idleclassic, но и для любого другого стиля, встроенного в Pygments. Отдельно устанавливать их не нужно. В дистрибутиве Anaconda 2 все заработает "с колес".

GUI-инструмент

Операции по подсветке кода Python выполнять быстрее и удобнее при помощи простого GUI-инструмента, код которого приводится ниже. Вам достаточно скопировать и вставить этот код в чистое окно любого редактора Python и запустить его на выполнение.

Откроются два окна: "Код Python" и "Код HTML". Вставьте код Python, который нужно "раскрасить", в первое окно. Работают стандартные клавиатурные сокращения: [Ctrl-c] для копирования, [Ctrl-x] для вырезания, [Ctrl-v] и [Shift-Ins] для вставки. После нажатия кнопки Подсветка начнется операции преобразования кода, которая может занять несколько секунд. Результат выводится во второе окно - "Код HTML". Он автоматически выделен. Его можно скопировать и вставить в нужный html-файл. Результат работы программы записывается также во вспомогательный файл x.html, расположенный в той же папке, что и сама программа. Если открыть x.html в браузере, можно сразу увидеть результат своей работы.

Инструмент нетрудно доработать так, чтобы можно было выбирать стиль подсветки, не только idleclassic.

# -*- coding: UTF-8 -*-
import os
from Tkinter import *
import ScrolledText as tkst
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter

# keys_font - шрифт, которым выводятся надписи на клавишах
keys_font="-*-arial-*-r-*-*-20-*-*-*-*-*-*-uni"

tk=Tk()
tk.title("Подсветка кода Python в стиле IDLE")

def convert():
    # В переменную contents помещается все содержимое окна "Код Python"
    contents=myCode.get(1.0,END)
    # Без следующей строки не получится подсвечивать код с символами юникод, например кириллицы
    contents2=contents.encode('utf8')
    # file_output - это временный файл x.py, в который будет выводиться введенный
    # пользователем код Python. Можно было бы использовать встроенный модуль
    # Python tempfile, специально предназначенный для работы с временными файлами,
    # но я решил перестраховаться: нет гарантии, что в 100% случаев команда pygmentize
    # будет видна из временного каталога, где Python создаст этот временный файл.
    # Например, если используется portable версия Python.
    file_output=open("x.py",'w')
    file_output.write(contents2)
    # Закрываем временный файл x.py, чтобы с ним смогла начать работать внешняя программа pygmentize
    file_output.close()
    # Главная команда программы, которая и выполняет преобразование
    os.popen('pygmentize -f html -O style=idleclassic\
              -P cssstyles="border: 1px solid grey;\
              padding: 3px" -P noclasses=True -o x.html x.py')
    # file_input - это файл x.html, в котором хранится подсвеченный код Python в формате html.
    # Он не удаляется по завершении работы программы
    file_input=open("x.html",'r')
    # html - строковая переменная, в которую будет записан преобразованный код в форфмате html
    html=file_input.read()
    myHtml.insert(END,html)
    #Фокус передается в окно myHtml. Без этого не будет видно выделение преобразованного кода
    myHtml.focus_set()
    # Преобразованный код во втором окне выделяется...
    myHtml.tag_add(SEL, "1.0", END)
    # ... и в принципе его можно автоматически копировать в буфер обмена.
    # Но такое поведение программы не очевидно для пользователя, поэтому
    # следующую строку я закомментировал.
    # myHtml.event_generate('<<Copy>>')
    file_input.close()

# Кнопка для запуска операции преобразования кода    
myButton=Button(tk,height=1,text="Подсветка",command=convert)
myButton.grid(row=0,column=0,columnspan=2)

# Метки для идентификации окон
label1=Label(tk, height=1, text="Код Python")
label1.grid(row=1,column=0)

label2=Label(tk, height=1, text="Код HTML")
label2.grid(row=1,column=1)

# Создаем элемент управления Text для кода Python, который нужно "раскрасить"
myCode=tkst.ScrolledText(tk,font=keys_font,width=50,height=20)
myCode.grid(row=2,column=0)

# Создаем еще один элемент управления Text для "подсвеченного" кода Python
# в формате html
myHtml=tkst.ScrolledText(tk,font=keys_font,width=50,height=20)
myHtml.grid(row=2,column=1)

# Если убрать следующие команды, при уменьшении размеров окна программы
# будут скрываться некоторые элементы управления
tk.grid_columnconfigure(0,weight=1)
tk.grid_columnconfigure(1,weight=1)
tk.grid_columnconfigure(2,weight=1)
tk.grid_rowconfigure(0,weight=1)
# Не понятно, почему параметр weight=10 фиксирует минимальный вертикальный размер ряда 0 
# при уменьшении высоты окна. minsize=20 аналогично фиксирует минимальную высоту ряда 1
tk.grid_rowconfigure(1,weight=10,minsize=20)
tk.grid_rowconfigure(2,weight=1)

# Эти функции и привязки нужны, чтобы клавиатурные комбинации <Ctrl-C>, <Ctrl-X>, <Ctrl-V>
# для операций копирования, врезания, вставки, соответственно, работали
# и на русской раскладке 
def copy1(event):
    myCode.event_generate('<<Copy>>')

def copy2(event):
    myHtml.event_generate('<<Copy>>')

def cut1(event):
    myCode.event_generate('<<Cut>>')

def cut2(event):
    myHtml.event_generate('<<Cut>>')

def paste1(event):
    myCode.event_generate('<<Paste>>')

def paste2(event):
    myHtml.event_generate('<<Paste>>')

myCode.bind("<Control-ntilde>", copy1)
myHtml.bind("<Control-ntilde>", copy2)
myCode.bind("<Control-division>", cut1)
myHtml.bind("<Control-division>", cut2)
myCode.bind("<Control-igrave>", paste1)
myHtml.bind("<Control-igrave>", paste2)

def _destroy(event):
    # Если не добавить это исключение, то при преждевременном закрытии окна программы
    # (до проведения обработки кода Python) интерпретатор будет сообщать, что
    # временного файла x.py не существует и его удалить нельзя
    try:
        os.remove("x.py")
    except OSError:
        pass

# Перехватывается команда на закрытие программы, чтобы с помощью процедуры
# _destroy удалить временный файл x.py, расположенный в той же папке, что  и сама программа
myCode.bind("<Destroy>", _destroy)

# Команда focus_set() автоматически размещает курсор в первом элементе управления Text 
myCode.focus_set()

tk.mainloop()

Python для инженеров и исследователей

Автор: Ф.С.Занько

Лицензия Creative Commons
Это произведение доступно по лицензии Creative Commons «Attribution-ShareAlike» («Атрибуция — На тех же условиях») 4.0 Всемирная.

О замеченных ошибках, неточностях, опечатках просьба сообщать по электронному адресу:
russianlutheran@gmail.com