Автоматична візуалізація python-коду. Частина друга: реалізація

першої частини статті були коротко обговорено блок-схеми та наявні інструменти для роботи з ними. Потім були обговорені всі графічні примітиви, необхідні для створення графічного представлення коду. Приклад середовища, що підтримує таке графічне представлення показаний на картинці нижче.

image
Середовище, що підтримує графічне представлення коду

У другій частині мова піде про реалізацію, виконаною, в основному, на Пітоні. Будуть обговорені реалізована і планована функціональність, а також пропонований мікро мову розмітки.



Загальна інформація
Реалізація технології виконана в рамках проекту з відкритими вихідними текстами, названого Коразмерності. Всі вихідні тексти доступні під ліцензією GPL v.3 і розміщені в трьох репозиторіях на github: два модуля розширення Пітона cdm-pythonparser і cdm-flowparser плюс власне середовище IDE. Модулі розширення, в основному, написані на C/C++, а IDE на Пітоні серії 2. Для графічної частини використовувалася Пітон обгортка бібліотеки QT — PyQT.

Розробка виконана на Linux і для Linux. В основному використовувався дистрибутив Ubuntu.

Середа призначена для роботи з проектами, написаними на Пітоні серії 2.

Архітектура
На діаграмі нижче представлена архітектура IDE.

image
Архітектура IDE

Блакитним на діаграмі позначено частини, розроблені у проекті. Жовтим — сторонні Пітон модулі, а зеленим — сторонні бінарні модулі.

З самого початку проекту було очевидно, що одному розробнику зовсім не під силу розробити всі необхідні компоненти з чистого аркуша в розумні терміни. Тому вже існуючі Пітон пакети використовувалися скрізь, де це було можливо та розумно. Наведена діаграма відмінно відображає прийняте рішення.

Тільки три частини розроблені в рамках проекту. IDE написана на Пітоні з метою прискорення розробки та спрощення проведення експериментів. Модулі розширення написані на C/C++ для кращої чуйності IDE. Завдання brief parser полягає в тому, щоб повідомити про всіх знайдених Пітон файлі (або буфері) сутності, таких як імпорти, класи, функції, глобальні змінні, рядки документації і т. д. Наявність такої інформації дозволяє реалізувати, наприклад, таку функціональність: структуровано показати вміст файла і забезпечити навігацію, надати аналіз певних, але ніде не використаних функцій, класів і глобальних змінних у проекті. Завдання flow parser надати в зручному вигляді дані, необхідні для відтворення діаграми.

Всі інші компоненти — сторонні. PyQT використовувалася для інтерфейсної і мережної частини. QScintilla в якості основного текстового редактора і деяких інших елементів, таких як перенаправленный введення/виведення відлагоджувати скриптів або показ svn версії файлу певної ревізії. Graphviz використовувався для розрахунку розташування графічних елементів діаграми залежностей тощо Також використовувалися й інші готові Пітон пакети: pyflakes, pylint, filemagic, rope, gprof2dot і т. д.

Конвеєр від коду до графіку
Реалізація переходу від тексту до графіку побудована за принципом конвеєра. На кожній стадії виконується певна частина роботи, а результати передаються на наступну стадію. Діаграма нижче показує всі стадії конвеєра, ліворуч якого на вхід поступає вихідний текст, а праворуч на виході виходить намальована діаграма.

image
Конвеєр від коду до графіку

Починається робота з побудови синтаксичного дерева з початкового тексту. Потім дерево обходиться, і всі виявлені блоки коду, цикли, функції і т. д. розкладаються в ієрархічну структуру даних. Після цього, за вихідного коду робиться ще один прохід, в результаті якого збирається інформація про коментарях. На подальших стадіях конвеєра зручніше мати коментарі вже асоційованими з распознанными конструкціями мови, а не як окремі дані. Тому наступним етапом виконується злиття коментарів з ієрархічною структурою, яка представляє код. Описані дії виконуються flow parser модулем розширення, який написаний на C/C++ для досягнення найкращої продуктивності.

Наступні стадії реалізовані вже всередині IDE і написані на Пітоні. Це забезпечує більшу легкість експериментування з відображенням у порівнянні з реалізацією на C++.

Спочатку в структурі даних, названої віртуальним полотном, розміщуються графічні елементи у відповідності зі структурою даних, отриманої від модуля розширення. Потім настає фаза рендеринга, основне завдання якої розрахувати розміри всіх графічних елементів. Нарешті, всі графічні елементи відмальовує належним чином.

Обговоримо всі ці стадії в деталях.

Побудова синтаксичного дерева
Це найперша стадія на шляху від тексту до графіку. Її завдання — парсинг вихідного тексту і складання ієрархічної структури даних. Це зручно робити за допомогою синтаксичного дерева, побудованого з початкового тексту. Очевидно, що розробляти новий парсер Пітона спеціально для проекту не хотілося, а навпаки, було бажання скористатися чимось вже готовим. На щастя, в поділюваної бібліотеці інтерпретатора Пітона знайшлася відповідна функція. Це C — функція, яка будує дерево в пам'яті для зазначеного коду. Для візуалізації роботи цієї функції була написана утиліта, яка наочно показує побудоване дерево. Наприклад, для початкового тексту:

#!/bin/env python
# encoding: latin-1

def f():
# What printed?
print 154

Буде побудовано таке дерево (для стислості приведений тільки фрагмент):

$ ./tree test.py
Type: encoding_decl line: 0 col: 0 str: iso-8859-1
Type: file_input line: 0 col: 0
Type: stmt line: 4 col: 0
Type: compound_stmt line: 4 col: 0
Type: funcdef line: 4 col: 0
Type: NAME line: 4 col: 0 str: def
Type: NAME line: 4 col: 4 str: f
Type: parameters line: 4 col: 5
Type: LPAR line: 4 col: 5 str: (
Type: RPAR line: 4 col: 6 str: )
Type: COLON line: 4 col: 7 str::
Type: suite line: 4 col: 8
Type: NEWLINE line: 4 col: 8 str:
Type: INDENT line: 6 col: -1 str:
Type: stmt line: 6 col: 4
Type: simple_stmt line: 6 col: 4
Type: small_stmt line: 6 col: 4
Type: print_stmt line: 6 col: 4
...

У висновку кожен рядок відповідає вузлу дерева, вкладеність показана відступами, а для вузлів показана вся доступна інформація.

Загалом, дерево виглядає дуже добре: є інформація про рядку і колонці, є тип кожного сайту, який відповідає формальній граматиці Пітона. Але є і проблеми. По-перше, в коді були коментарі, але інформація про них в дереві немає. По-друге, інформація про номери рядка і колонки для кодування не відповідає дійсності. По-третє, сама назва кодування змінилося. У коді була latin-1, а синтаксичне дерево рапортує iso-8859-1. У разі багаторядкових строкових літералів теж є проблема: у дереві немає інформації про номери рядків. Всі ці сюрпризи повинні бути враховано в коді, який займається обходом дерева. Проте всі описані проблеми швидше дрібниці, порівняно зі складністю цілого парсера.

У модулі розширення визначаються типи, які будуть видні в Пітон коді на наступних стадіях. Типи відповідають всім пізнаваних елементи, наприклад Class, Import, Break і т. д. Крім специфічних для кожного випадку членів даних і функцій, що всі вони призначені для опису елемента в термінах фрагментів: де шматочок тексту починається і де закінчується.

При обході дерева формується ієрархічна структура, екземпляр класу ControlFlow, який покладені всі розпізнані елементи потрібним чином.

Збір коментарів
З-за того, що інформації про коментарях не виявилося в синтаксичному дереві (очевидно, що інтерпретатору в них немає необхідності), а вони потрібні для відображення коду без втрат, довелося вводити додатковий прохід по вихідного коду. За цей прохід витягується інформація про кожному рядку коментаря. Зробити це просто, завдяки простій граматиці Пітона і відсутності як багаторядкових коментарів, так і препроцесора.

Коментарі збираються у вигляді списку фрагментів, де кожен фрагмент описує одну сходинку коментаря набором атрибутів: номер рядка, номер колонки початку і кінця, абсолютні позиції у файлі початку і кінця коментаря.

Наприклад, для коду:

#!/bin/env python
# encoding: latin-1

def f():
# What printed?
print 154

Буде зібрано три фрагмента виду:

Line: 1 Pos: 1…
Line: 2 Pos: 1…
Line: 5 Pos: 5…

Злиття коментарів з фрагментами коду
При побудові діаграми зручніше мати справу не з двома різними структурами даних — програмний код і коментарі — а з одного. Це спрощує процес розміщення елементів на віртуальному полотні. Тому в модулі розширення виконується ще один етап: злиття коментарів з распознанными елементами.

Розглянемо приклад:

# leading comment
a = 10 # side 1 comment
# side comment 2


image
Злиття коментарів з кодом

В результаті проходу по синтаксичному дереву для коду вище буде сформований, в числі інших, екземпляр класу CodeBlock. Він, в числі інших полів, має поля body, leadingComment і sideComment, що описують відповідні елементи в термінах фрагментів. Поле body буде заповнений інформацією з синтаксичного дерева, а поля коментарів будуть містити None.

За результатами проходу для збору коментарів буде сформовано список з трьох фрагментів. При злитті перший фрагмент буде використаний для заповнення поля leadingComment в CodeBlock, а другий і третій фрагменти поля sideComment. Злиття відбувається на основі номерів рядків, доступних для обох джерел інформації.

Таким чином, на виході етапу злиття є повністю готова єдина ієрархічна структура даних про вміст файлу або буфера пам'яті.

Продуктивність модуля
Описані вище стадії конвеєра написані на C/C++ та оформлені у вигляді Пітон модуля. Із загальних міркувань, роботу всіх цих стадій хотілося зробити швидкої, щоб уникнути неприємних затримок при перерисовках діаграм в паузах модифікації тексту. Для перевірки продуктивності модуль був запущений на наявній платформі:
  • Intel Core i5-3210M ноутбук
  • Ubuntu 14.04 LTS
для обробки всіх файлів стандартної інсталяції Пітона 2.7.6. При наявності 5707 файлів обробка зайняла близько 6 секунд. Звичайно, файли мають різний розмір і від нього залежить час роботи модуля, але результат в середньому близько 1 мілісекунди на файл не на самому швидкому обладнанні, мені здається більш ніж прийнятним. На практиці текст, який потрібно обробити, найчастіше вже міститься в пам'яті і час дискових операцій йде зовсім, що також позитивно впливає на продуктивність.

Розміщення на віртуальному полотні
Мета цієї стадії конвеєра — розмістити на віртуальному полотні всі необхідні елементи з урахуванням взаємозв'язків між ними. Віртуальний полотно можна уявити собі як полотно з прямокутними осередками. Клітинка може бути порожньою, може містити один графічний елемент або файл віртуальний полотно. На даному етапі важливо тільки взаємне розміщення елементів, а не точні розміри.

При цьому полотно не має фіксованого розміру і може рости вниз і вправо по мірі потреби. Такий підхід відповідає підготовленій структурі даних і способу малювання діаграми. Починається процес в лівому верхньому кутку. У міру потреби додаються нові рядка і колонки. Наприклад, для наступного блоку коду буде додано новий рядок, а якщо у блоку є бічній коментар — то нова колонка.

Набір графічних елементів, які можуть бути розміщені в клітинках, приблизно відповідає пізнаваних елементів мови з невеликим розширенням. Наприклад, в комірці може знадобитися з'єднувач, провідний зверху вниз, а в мові такий елемент відсутній.

Для віртуального полотна використовується список списків (двовимірний масив), порожній на початку процесу.

Розглянемо простий приклад для ілюстрації процесу.

a = 10 # side 1 comment
# side comment 2


image
Розміщення графічних елементів на полотні

Зліва на картинці вище показана структура даних, сформована за результатами аналізу коду. Примірник ControlFlow містить кілька атрибутів і контейнер suite, в якому всього один елемент — примірник CodeBlock.

У вихідному стані полотно порожній, і починається обхід ControlFlow. Модуль було вирішено малювати як область видимості, тобто як прямокутник із закругленими краями. Для зручності подальших розрахунків розмірів графічних елементів з урахуванням відступів, прямокутник області видимості умовно розбитий на складові: грані і кути. У самому верхньому куті діаграми буде знаходитися лівий верхній кут прямокутника модуля, тому додаємо новий рядок до полотна, а в рядку додаємо одну колонку і поміщаємо в клітинку scope corner елемент. Верхню межу прямокутника можна не розміщувати правіше, так як запас по вертикалі вже є за рахунок першої клітинки, а побудова прямокутника все одно буде здійснюватися як єдина фігура в момент, коли буде виявлений scope corner на етапі обходу полотна.

Переходимо до наступного рядка. У модуля є заголовок, в якому вказані рядок запуску і кодування. Значення відповідних полів None, але заголовок все одно треба малювати. Тому додаємо до полотна новий рядок. На діаграмі заголовок повинен знаходитися усередині прямокутника з невеликим відступом, тому відразу розміщувати заголовок у створеній рядку не можна. У першій комірці повинна бути поміщена ліва грань, а потім заголовок. Тому додаємо дві колонки і в першій розміщуємо scope left, а в другій — scope header. Розміщувати праву грань третьої комірці не потрібно. По-перше, зараз ще невідомо скільки колонок буде в самій широкій рядку. А по-друге, прямокутник області видимості все одно буде намальований у момент виявлення scope corner.

У модуля могла б бути рядок документації, і для неї знадобилося б ще один рядок. Але рядки документації немає, тому переходимо до suite. Перший елемент в suite — це блок коду. Додаємо новий рядок, а в неї додаємо колонку для лівій грані. Потім додаємо ще одну колонку і розміщуємо в комірці графічний елемент для блоку коду. У прикладі у блоку є бічній коментар, який повинен розташовуватися праворуч, тому додаємо ще одну колонку і розташовуємо в комірці бічній коментар.

Більше suite немає елементів, тому процес підготовки віртуального полотна закінчується. Лівий нижній кут прямокутника і нижню межу можна не додавати з причин, подібних описаним вище для верхньої і правої граней. Необхідно лише врахувати, що вони розуміються при розрахунку геометричних розмірів графічних елементів.

Рендеринг
Завдання цієї стадії конвеєра полягає в обчисленні розмірів всіх графічних примітивів для малювання на екрані. Робиться це шляхом обходу всіх розміщених осередків, обчислення необхідних розмірів і збереження їх в атрибутах комірки.

Кожна комірка має дві обчислених ширини і дві висоти — мінімально необхідні і фактично необхідні з урахуванням розмірів сусідніх осередків.

Спочатку обговоримо, як розраховується висота. Відбувається це построково. Розглянемо рядок, в якій розміщені елементи, відповідні оператора присвоювання. Тут видно, що оператор присвоювання займає один рядок, а коментар — дві. Значить, клітинка з коментарем зажадає більше вертикальних пікселів на екрані при відображенні. З іншого боку, всі клітинки в рядку повинні бути однієї висоти, інакше осередку нижче будуть намальовані зі зміщенням. Звідси випливає простий алгоритм. Необхідно обійти всі клітинки в рядку і розрахувати для кожної мінімальну висоту. Потім вибрати максимальне значення з тільки що обчислених і зберегти його як фактично необхідну висоту.

Трохи складніше справа йде з розрахунком ширини комірок. З цієї точки зору є два типи рядків:
  • такі, у яких ширина повинна розраховуватися з урахуванням ширини комірок в сусідньому рядку
  • такі, ширина комірок яких може розраховуватись без урахування сусідніх рядків
Хорошим прикладом залежних рядків є оператор if. Гілка, яка буде намальована під блоком умови, може бути довільної складності, а отже, й довільної ширини. А друга гілка, яка повинна бути намальована праворуч, має з'єднувач від блоку умови, що знаходиться в рядку вище. Значить, ширина комірки з'єднувача повинна бути розрахована в залежності від рядків, розташованих нижче.

Таким чином, для незалежних рядків ширина розраховується за один прохід і мінімальна ширина збігається з фактичною.

Для регіонів залежних рядків алгоритм складніше. Спочатку розраховуються мінімальні ширини всіх осередків у регіоні. А потім для кожної колонки розраховується фактична ширина як максимальне значення мінімально необхідної ширини для всіх клітинок у колонці регіону. Тобто дуже схоже на те, що зроблено для обчислення висоти в рядку.

Обчислення проводяться рекурсивно для вкладених віртуальних полотен. При обчисленнях враховуються різні налаштування: метрика вибраного шрифту, поля для різних осередків, відступи тексту і т. п. По завершенню роботи фази все необхідне вже підготовлено для розміщення графічних примітивів вже на екранному полотні.

Малювання
Стадія малювання дуже проста. Так як для інтерфейсу користувача використовується бібліотека QT, то створюється графічна сцена з розрахованими на попередньому етапі розмірами. Потім здійснюється рекурсивний обхід віртуального полотна і на графічну сцену додаються необхідні елементи з потрібними координатами.

Процес обходу починається з верхнього лівого кута та поточні координати встановлюються в 0, 0. Потім обходиться рядок, після обробки кожної клітинки ширина додається до поточної координати x. При переході до наступного рядка, координата x скидається в 0, а до координаті y додається висота щойно обробленої рядка.

На цьому процес отримання графіки за кодом закінчується.

Теперішнє і майбутнє
Обговоримо тепер функціональність, яка вже реалізована і те, що можна додати в майбутньому.

Список того, що зроблено, досить короткий:
  • Автоматичне оновлення діаграми в паузах зміни коду.
  • Ручна синхронізація видимих тексту і графіки в обох напрямках. Якщо курсор знаходиться в текстовому редакторі, і натиснута спеціальна комбінація клавіш, то на діаграмі виконується пошук примітиву, найбільш відповідного поточного положення курсора. Далі примітив підсвічується, а діаграма прокручується так, щоб зробити примітив видимим. У зворотному напрямку синхронізація виконується за подвійним клацанням по примітиву, який призводить до переміщення текстового курсору до потрібної рядку коду та прокрутці текстового редактора, якщо необхідно.
  • Масштаб діаграми. Поточна реалізація використовує вбудовані засоби масштабування бібліотеки QT. В майбутньому планується замінити її на масштабування через зміна розміру шрифту і перерахунок розмірів всіх елементів.
  • Експорт діаграми у PDF, PNG і SVG. Якість вихідних документів визначається реалізацією бібліотеки QT, так як саме її кошти використані для цієї функціональності.
  • Навігаційна панель областей видимості. Графіка інтенсивно використовує ідею області видимості, тому типова діаграма містить безліч вкладених областей. Навігаційна панель показує поточний шлях в термінах вкладених областей видимості для поточної позиції курсору миші над графічною сценою.
  • Індивідуальне перемикання розміщення гілок для оператора if. За замовчуванням гілка N малюється нижче, а гілка Y правіше. Діаграма дозволяє поміняти місцями розташування гілок, використовуючи контекстне меню блоку умови.
  • Індивідуальна заміна тексту будь-якого графічного примітиву. Іноді виникає бажання замінити текст якого-небудь блоку на довільний. Наприклад, умова в термінах змінних і викликів функцій може бути довгим і зовсім не очевидним, тоді як фраза на природній мові може краще описати те, що відбувається. Діаграма дозволяє замінити текст на довільний і показує вихідний у підказці.
  • Індивідуальна заміна кольорів кожного примітиву. Іноді виникає бажання привернути увагу до якого-небудь ділянці коду шляхом підсвічування графічних примітивів. Наприклад, потенційно небезпечний ділянку можна підсвітити червоним кольором або вибрати загальний колір для елементів, що відповідають за загальну функціональність. Діаграма дозволяє змінити кольори фону, шрифту і обведення примітивів.
Спільне застосування вже реалізованих індивідуальних змін примітивів, як показує практика, може істотно змінити вигляд діаграми.

Можливості, якими можна доповнити наявну основу, обмежуються тільки фантазією. Тут перераховані найбільш очевидні.
  • Автоматична синхронізація тексту і графіки при прокручуванні.
  • Підтримка редагування діаграмі: переміщення, видалення та додавання блоків. Редагування тексту всередині окремих блоків. Копіювання і вставка блоків.
  • Підтримка групових операцій з блоками.
  • Візуалізація налагодження на діаграмі. Як мінімум підсвічування поточного блоку і поточного рядка в ньому.
  • Підтримка пошуку на діаграмі.
  • Підтримка друку.
  • Управління приховуванням / показом різних елементів: коментарів рядків документації, тел функцій, класів, циклів і т. п.
  • Підсвічування різних типів импортов: всередині проекту, системні, непізнані.
  • Підтримка додаткових немовних блоків або картинок на діаграмах.
  • Розумне масштабування. Можна ввести декілька фіксованих рівнів масштабу: всі елементи, без коментарів і рядків документації, тільки заголовки класів і функцій, залежності між файлами в підкаталозі і покажчики зовнішніх зв'язків. Якщо закріпити таке поведінка за колесом миші з яким-небудь модифікатором, то можна буде отримувати підсумкову інформацію надзвичайно швидко.
  • Згортка декількох блоків в один і розгортання назад. Група блоків, що виконують спільне завдання може бути виділена на діаграмі і згорнута в один блок зі своєю власною графікою і наданим текстом. Природне обмеження тут — група повинна мати один вхід і один вихід. Така функціональність може стати в нагоді при роботі з невідомим кодом. Коли приходить розуміння, що роблять кілька розташованих блоків, можна скоротити складність діаграми, об'єднавши групу і замінивши її одним блоком з, потрібної підписом, наприклад «MD5 calculation». Зрозуміло, в будь-який момент можна буде повернутися до подробиць. Цю функцію можна розглядати як введення третього виміру в діаграму.


CML v.1
Можливості, перераховані в попередньому розділі, можна розділити на дві групи:
  • Вимагають збереження інформації у зв'язку з кодом.
  • Повністю незалежні від коду.
Наприклад функціональність масштабування абсолютно не залежить від коду. Поточний масштаб, швидше, має бути збережений як поточна налаштування IDE.

З іншого боку, перемикання гілок if пов'язано з конкретним оператором і інформація про це повинна бути якимось чином збережена. Адже при наступній сесії роботи if повинен бути намальований так, як було запропоновано раніше.

Очевидно, що є два шляхи збереження додаткової інформації: або прямо в початковому тексті, або в окремому файлі або навіть безлічі файлів. При прийнятті рішення були прийняті до уваги такі міркування:
  • Уявімо собі, що над проектом працює команда розробників і частина з них з успіхом використовує графічні можливості представлення коду. А інша частина з принципових міркувань для роботи з кодом використовує тільки vim. У цьому разі, якщо додаткова інформація зберігається окремо від коду, то її консистентним при поперемінному редагуванні коду членами різних таборів буде підтримати надзвичайно складно, якщо взагалі можливо. Напевно додаткова інформація виявиться не відповідає дійсності в якийсь момент часу.
  • Якщо вибрано підхід додаткових файлів, то вони швидше засмічують вміст проекту і вимагають додаткових зусиль від команди при роботі з системами контролю версій.
  • Коли розробник вводить додаткову розмітку — наприклад замінює довгий код незрозумілого умови підходящої фрази — це робиться не для розваги, а тому, що така відмітка має цінність. Добре б зберегти цю цінність доступною і для тих, хто не користується графікою хоча б і не в такому гарному вигляді.
Таким чином, якщо є компактне рішення для збереження додаткової інформації безпосередньо у файли з вихідним текстом, то краще скористатися ним. Таке рішення знайшлося і було названо CML: Коразмерності markup language.

CML — це мікро мова розмітки, що використовує коментарі пітона. Кожен CML коментар складається з однієї або кількох сусідніх рядків. Формат першого рядка обраний наступним:

# cml <версія> <тип> [пари ключ=значення]

А формат рядків продовження наступним:

# cml+ <продовження попередньої cml рядка>

Літерали cml і cml+ це те, що відрізняє CML коментар від інших. Версія, що представляє з себе ціле число, введена в розрахунку на майбутнє, якщо CML буде еволюціонувати. Тип визначає як саме вплине коментар на діаграму. В якості типу використовується рядковий ідентифікатор, наприклад rt (скорочення від replace text). А пари ключ=значення надають можливість описати всі необхідні параметри.

Як видно, формат простий і легко читається людиною. Таким чином задовольняється вимога можливості отримання додаткової корисної інформації не тільки при використанні IDE, але і при перегляді тексту. При цьому єдиним добровільною угодою між тими, хто використовує і не використовує графіку є таке: не поламати CML коментарі.

CML: заміна тексту
Розпізнавання CML коментаря для заміни тексту вже реалізовано. Він може з'явитися як лідируючий коментар перед блоком, наприклад:

# cml 1 rt text="Believe me, I do the right thing here"
False = 154

image
Блок коду зі зміненим текстом

Підтримки з боку графічного інтерфейсу поки немає. Додати коментар зараз можна тільки з текстового редактора. Призначення параметра text цілком очевидно, а тип rt вибраний виходячи з скорочення слів replace text.

CML: перемикання гілок if
Розпізнавання CML коментаря для перемикання гілок if також вже реалізовано. Підтримка є як з боку тексту, так і з боку графіки. За вибором з контекстного меню блоку умови коментар буде вставлений в потрібне місце коду, а потім діаграма генерується заново.

# cml 1 sw
if False == 154:
print("that's expected")
else:
print("Hmmm, has the code above been run?")

image
Оператор if з гілкою N праворуч

У наведеному прикладі гілка N намальована праворуч від умови.

Видно, що цей CML коментар не вимагає ніяких параметрів. А його тип sw вибраний виходячи з скорочення слова switch.

CML: зміна кольору
Розпізнавання CML коментаря для зміни кольору вже реалізовано. Він може з'явитися як лідируючий коментар перед блоком, наприклад:

# cml 1 cc background="255,138,128"
# cml+ foreground="0,0,255"
# cml+ border="0,0,0"
print("Danger! Someone has damaged False")


image
Блок з індивідуальними квітами

Підтримується зміна кольору для фону (background), колір шрифту (foreground) і кольору граней (параметр border). Тип cc вибраний виходячи з скорочення слів custom colors.

Підтримки з боку графічного інтерфейсу поки немає. Додати коментар зараз можна тільки з текстового редактора.

CML: згортка групи
Підтримки цього типу коментаря зараз немає, проте вже зрозуміло, як функціональність може бути реалізована.

Послідовність дій може бути такою. Користувач виділяє на діаграмі групу блоків з урахуванням обмеження: група має один вхід і один вихід. Далі з контекстного меню вибирається пункт: об'єднати в групу. Потім користувач вводить назву блоку, який буде намальований замість групи. По закінченню введення діаграма перефарбували в оновленому вигляді.

Очевидно, що для групи як єдиної сутності, є точки в коді де вона починається і де вона закінчується. Значить, ці місця можна вставити коментарі CML, наприклад такі:

# cml gb uuid="..." title="..."
. . .
# cml ge uuid="..."

Тут параметр uuid автоматично генерується в момент створення групи і потрібен він для того, щоб правильно знаходити пари початку групи і її кінця, так як рівнів вкладеності може бути скільки завгодно. Призначення параметра title очевидно — це текст, введений користувачем. Типи записів gb і ge введені з міркування скорочень слів begin group і group end відповідно.

Наявність uuid також дозволяє діагностувати різні помилки. Наприклад, в результаті редагування тексту один з пари CML коментарів міг бути вилучений. Ще один випадок можливого застосування uuid — запам'ятовування в IDE груп, які повинні бути показані в наступній сесії як згорнуті.

Побічні ефекти
Практика використання інструменту показала, що у технології є цікаві побічні ефекти, які абсолютно не розглядалися при первинній розробці.

По-перше, виявилося зручним використовувати згенеровані діаграми для документації і для обговорення з колегами, часто не мають відношення до програмування, але які є експертами предметної області. У таких випадках готувався код, не призначений для виконання, але відповідає логіці дій і відповідає формального синтаксису пітона. Згенерована діаграма або вставлялася в документацію, або друкувалася і обговорювалася. Додаткова зручність проявилося в легкості внесення змін у логіку — діаграма моментально перемальовується з усіма потрібними відступами і вирівнюємо без необхідності ручних операцій з графікою.

По-друге, виявився цікавий чисто психологічний ефект. Розробник, відкриваючи свій же давно написаний код з використанням Коразмерності помічав, що діаграма виглядає негарно — занадто складна чи заплутана. І з метою отримання більш витонченою діаграми вносив зміни в текст, фактично виконуючи рефакторинг і спрощення коду. Що в свою чергу призводить до зменшення складності розуміння і подальшої підтримки коду.

По-третє, незважаючи на те, що розробка виконана для Пітона, технологія цілком може бути поширена і на інші мови програмування. Пітон був обраний як полігон для випробувань з кількох причин: мова популярний, але в той же час синтаксично простий.

Подяки
Я б хотів подякувати всім, хто допомагав у роботі над цим проектом. Спасибі моїм колегам Дмитру Казимирову, Іллі Loginovu, Девіду Макэлхани і Сергію Фуканчику за допомогу з різними аспектами розробки на різних етапах.

Окремі подяки авторам і розробникам Пітон пакетів з відкритими вихідними текстами, які були використані в роботі над Коразмерності IDE.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.