Донецкий техникум промышленной автоматики

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

  1. Загальна інформація
  2. архітектура
  3. Конвеєр від коду до графіку
  4. Побудова синтаксичного дерева
  5. збір коментарів
  6. Злиття коментарів з фрагментами коду
  7. продуктивність модуля
  8. Розміщення на віртуальному полотні
  9. Візуалізація
  10. малювання
  11. Сьогодення та майбутнє
  12. CML v.1
  13. CML: заміна тексту
  14. CML: перемикання гілок if
  15. CML: зміна кольору
  16. CML: згортка групи
  17. Побічні ЕФЕКТ
  18. Подякою

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

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

Загальна інформація

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

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

Середовище налаштовано для роботи з проектами, написаними на Python серії 2.

архітектура

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

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

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

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

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

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

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

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

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

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

Наступні стадії реалізовані вже всередині IDE і написані на Python. Це забезпечує більшу легкість експериментування з отрисовкой в ​​порівнянні з реалізацією на 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 comment 1 # side comment 2 # Leading comment a = 10 # side comment 1 # side comment 2   Злиття коментарів з кодом
Злиття коментарів з кодом

В результаті проходу по синтаксичному дереву для коду вище буде сформований, в числі інших, екземпляр класу 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 comment 1 # side comment 2 a = 10 # side comment 1 # side comment 2   Розміщення графічних елементів на полотні
Розміщення графічних елементів на полотні

Зліва на зображенні вище показана структура даних, сформована за результатами аналізу коду. Примірник 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: Codimension 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 # Cml 1 rt text = Believe me, I do the right thing here False = 154   Блок коду зі зміненим текстом
Блок коду зі зміненим текстом

Підтримки з боку графічного інтерфейсу поки немає. Додати такий коментар зараз можна тільки з текстового редактора. Призначення параметра 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?") # Cml 1 sw if False == 154: print ( That's expected) else: print ( Hmmm, has the code above been run
Оператор 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") # Cml 1 cc background = 255,138,128 # cml + foreground = 0,0,255 # cml + border = 0,0,0 print ( Danger
Блок з індивідуальними квітами

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

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

CML: згортка групи

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

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

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

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

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

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

Побічні ЕФЕКТ

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

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

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

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

Подякою

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

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

Автор: SergeySatskiy

джерело

Bin / env python # encoding: latin-1 def f (): # What printed?
Bin / env python # encoding: latin-1 def f (): # What printed?
Hmmm, has the code above been run?