Оформление кода lsp

Как-то увидел ссылку на http://www.cad-notes.com/good-autolisp-programming-techniques/. Почти со всем не согласен :) Расскажу почему

Поехали с самого начала.
Во-первых, все сказанное в статье касается написания и чтения кода, но никак не общей настройки среды и отладки кода. А это вопросы тоже немаловажные. Исправляем недочет :)

Настройка VLIDE
Английский AutoCAD
Русский AutoCAD
Пояснение
vlide_en_settings01

vlide_ru_settings01

Вызывает диалог “Оформление окна”. Там тьма интересностей, но лично я обычно меняю там только шаг табуляции с 8 на 2. Ну не люблю я, когда по нажатию на [Tab] текст ускакивает непонятно куда :)
На появляющийся запрос, естественно, отвечаем “Да”
vlide_en_settings02

vlide_ru_settings02

Выводит диалог общих настроек. Привожу свою расшифровку самых интересных и важных (с моей точки зрения) переключателей:

Закладка General / Общие

vlide_en_settings03 vlide_ru_settings03
Backup the file… / Создавать резервную копию… В общем, понятно – при первом сохранении после открытия будет рядышком положен файл с таким же именем, но расширением ._ls / _.dc / ._mn. Весьма удобно. Ставлю всегда
Make backup by copy… / Сохранять резервную копию, не переименовывать… Создает копию исходного файла. Если этот параметр не выбран, файл резервной копии является переименованной версией исходного файла. Долго экспериментировал, но никаких внятных результатов получить не смог. Поэтому снимаю.
Group typing for… / Группировать для… Ставится, если лениво нажимать Ctrl+Z на каждый символ. Обычно ставлю
SETQ for protected symbols / SETQ для зарезервированных выражений Известно, что в lisp в принципе можно написать и такое:

1
(setq nil 1)

Но nil (и масса других элементов) являются зарезервированными словами и именами функций. Чтобы случайно не поменять их, лучше всего сразу получить соответствующее предупреждение, установив либо “Prompt to enter break loop” (“Подсказка для входа в цикл останова”), либо “Error” (“Ошибка”)

Закладка Diagnostic / Диагностические

vlide_en_settings04 vlide_ru_settings04

Тут уже придется почти все расшифровывать :)

Report statistic… / Выод статистики… Ставим. Обеспечивает вывод результатов проверки кода и компиляции каждой определенной функции т.н. “верхнего” уровня (т.е. не локальных)
Print top level… / Печать результатов верхнего уровня… Ставим. Если код корректно написан, при загрузке в консоли VLIDE выводится сообщение о корректности загрузки
Print notifications… / Печать уведомляющего сообщения… Как правило, ставлю. При вызове функции (load) в консоль выводится сообщение о загружаемом коде и результатах загрузки
Echo PRINx… / Эхо-вывод PRINx… По вкусу. Если установлено, то вызов функций princ, print, prin1 выводит результат не только в ком.строку AutoCAD, но и в консоль VLIDE
Inspect drawing objects… / Подробное изучение объектов… Обычно ставлю. Если снять, то в окне проверки значений (Inspect) выводится маловато информации, если она касается именно объектов dwg
Do not debug top-level / Без отладки верхнего уровня Насколько я понял: если установлено, и при этом установлен режим Stop Once (о нем чуть позже), то сначала будет выполнена попытка загрузки кода, а только потом будет вызываться остановка (неважно как ее инициируют)

Осталось совсем чуть-чуть.

vlide_en_settings05 vlide_ru_settings05

Обязательно устанавливаем флажок Break on error / Прервать на ошибке. Это позволит в случае ошибки остановить выполнение и через Ctrl + Shift + R вызвать окно трассировки ошибки.
Флажок Stop Once / Остановить, помимо того, что было сказано выше, позволяет автоматически открывать исходный код вызываемых пользовательских функций (конечно, если они были загружены как lsp, а не как fas / vlx).
Animation / Анимация и Trace command / Трассировка команд никогда не ставил. Пару раз поигрался, но явной пользы не увидел.

Дальше, если скриншоты и будут, то только для английской версии. Ну надоело мне параллельно запускать два AutoCAD'а :)
Форматирование. Не спорю, вещь нужная. Но каждый раз целиться в кнопочку - нереально. Уж проще нажать сочетания клавиш (см. Полезности в редакторе VLIDE и Полезности в редакторе VLIDE, часть 2.
А так - да, читать неформатированный код очень тяжело. Но все дело в том, что требования к "читабельности" кода у всех могут быть разными.
Для начала предлагаю рассмотреть несколько вариантов настройки форматирования
Именно от этого будет зависеть вид кода.
Вызовем окно настройки форматирования кода
vlide_ru_settings06
Сразу нажимаем кнопку More options и получаем окно наподобие
vlide_ru_settings07
Теперь поехали

Right text margin Правая граница текста. Если текст вдруг оказывается длиннее указанного значения, VLIDE попробует его перенести на следующую строку. Лично я часто ставлю 200 – и удобно, и места много не занимает
Narrow style indentation Грубо говоря, отступ для подчиненных элементов. Ставлю равным отступу табуляции (2)
Maximun wide-style car length Никогда не менял. Поэтому что делает и зачем оно вообще есть – не очень понимаю.
Single-Semicolon Comment Indentation Определяет, где будет располагаться комментарий, определенный одним символом “;”. Обычно я ставлю равным 10
Closing paren style Определяет режим расположения “закрывающей скобки” – на той же линии, с внутренним отступом или по границе “родителя”. Лично я обычно ставлю “с внутренним отступом”
Insert tabs Вставлять вместо пробелом символы табуляции. Лично мне такой режим не кажется нормальным, поэтому я галочку снимаю.
Save Formatting Options in Source File Не ставлю никогда. Суть в следующем: параметры формирования, которые я для себя определил как “идеальные”, записываются напрямую в lsp-файл. Вроде бы ничего страшного – до тех пор, пока мой lsp (то бишь исходник) не отправляется кому-то другому. Если вдруг этот кто-то другой откроет lsp в VLIDE, и выполнит загрузку именно через VLIDE, у него параметры форматирования кода станут как у меня. Круто? Ага, щщас! У человека вполне может оказаться свой набор настроек, который он долго и упорно вычислял и устанавливал – и я все ему порушил в долю секунды. Так что флажок не ставлю, и никому не советую.
А если вдруг в конце файла lsp есть комментарии типа “Visual LISP format…”, то эти комментарии сначала удаляем, а потом уже грузим полученный файл.

Хотелось бы привести различные варианты настройки форматирования и результаты обработки кода (я его специально сделал таким неудобоваримым)

1
(vl-load-com)(defun vl-browsefolder (caption / shlObj folder fldObj outVal) (setq shlObj (vla-GetInterfaceObject (vlax-get-acad-object) "Shell.Application")  folder (vlax-invoke-method shlObj 'BrowseForFolder (vla-get-HWND (vlax-get-acad-object)) caption (+ 512 16))) (vlax-release-object shlObj) (if folder (progn (setq fldObj (vlax-get-property folder 'Self) outVal (vlax-get-property fldObj 'Path)) (vlax-release-object folder) (vlax-release-object fldObj))) outVal)
vlide_format_01
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(vl-load-com)
(defun vl-browsefolder  (caption / shlObj folder fldObj outVal)
  (setq shlObj (vla-GetInterfaceObject
     (vlax-get-acad-object)
     "Shell.Application")
  folder (vlax-invoke-method
     shlObj
     'BrowseForFolder
     (vla-get-HWND (vlax-get-acad-object))
     caption
     (+ 512 16)))
  (vlax-release-object shlObj)
  (if folder
    (progn (setq fldObj (vlax-get-property folder 'Self)
     outVal (vlax-get-property fldObj 'Path))
     (vlax-release-object folder)
     (vlax-release-object fldObj)))
  outVal)
vlide_format02
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(vl-load-com)
(defun vl-browsefolder (caption / shlobj folder fldobj outval)
  (setq shlobj (vla-getinterfaceobject
                 (vlax-get-acad-object)
                 "Shell.Application"
                 ) ;_ end of vla-GetInterfaceObject
        folder (vlax-invoke-method
                 shlobj
                 'browseforfolder
                 (vla-get-hwnd (vlax-get-acad-object))
                 caption
                 (+ 512 16)
                 ) ;_ end of vlax-invoke-method
        ) ;_ end of setq
  (vlax-release-object shlobj)
  (if folder
    (progn (setq fldobj (vlax-get-property folder 'self)
                 outval (vlax-get-property fldobj 'path)
                 ) ;_ end of setq
           (vlax-release-object folder)
           (vlax-release-object fldobj)
           ) ;_ end of progn
    ) ;_ end of if
  outval
  ) ;_ end of defun
vlide_format03
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(vl-load-com)
(defun vl-browsefolder (caption / shlobj folder fldobj outval)
  (setq shlobj (vla-getinterfaceobject (vlax-get-acad-object) "Shell.Application")
        folder (vlax-invoke-method
                 shlobj
                 'browseforfolder
                 (vla-get-hwnd (vlax-get-acad-object))
                 caption
                 (+ 512 16)
                 ) ;_ end of vlax-invoke-method
        ) ;_ end of setq
  (vlax-release-object shlobj)
  (if folder
    (progn (setq fldobj (vlax-get-property folder 'self)
                 outval (vlax-get-property fldobj 'path)
                 ) ;_ end of setq
           (vlax-release-object folder)
           (vlax-release-object fldobj)
           ) ;_ end of progn
    ) ;_ end of if
  outval
  ) ;_ end of defun

Ну и так далее. Найти свое форматирование бывает непросто. По крайней мере мне было сложно, переходя с 17-дюймовых мониторов на 24 и обратно ;)

Комментирование
Как ни парадоксально, но комментирование кода может тоже вызывать некоторые затруднения.
Точнее, не само по себе комментирование – а то, что вообще под этим словом понимать.
Для себя я сейчас принял, что хорошо код нормально документированной функции должен строиться по определенным правилам (лет 10 назад правила были другие, сознаюсь честно):
Сначала следует собственно определение функции, с указанием параметров и локальных переменных / функций.
Потом в многострочном комментарии указывается – что делает функция; какие значения могут быть у параметров вызова; описание каждого параметра; возвращаемое значение и (почти всегда) пример вызова.
Комментарии внутри кода функции не являются критичными и могут быть, как правило, безболезненно удалены.
Так, уже рассмотренный выше код можно “задокументировать” и “откомментировать” примерно следующим образом:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(vl-load-com)
(defun vl-browsefolder (caption / shlobj folder fldobj outval)
  ;|
*    Вызывает окно выбора каталога, без отображения файлов внутри каталогов.
*    Оригинал взят: http://www.autocad.ru/cgi-bin/f1/board.cgi?t=21054YY
*    Параметры вызова:
  caption   показываемый заголовок (пояснение) окна
*    Возвращает выбранный каталог либо nil в случае ошибки / отмены пользователем
*    Примеры вызова:
(vl-browsefolder "Укажите каталог расположения шаблона")
|;

  (setq shlobj (vla-getinterfaceobject (vlax-get-acad-object) "Shell.Application")
        folder (vlax-invoke-method
                 shlobj
                 'browseforfolder
                 (vla-get-hwnd (vlax-get-acad-object))
                 caption
                 (+ 512 16)
                 ) ;_ end of vlax-invoke-method
        ) ;_ end of setq
  (vlax-release-object shlobj)
  (if folder
    (progn (setq fldobj (vlax-get-property folder 'self)
                 outval (vlax-get-property fldobj 'path)
                 ) ;_ end of setq
           (vlax-release-object folder)
           (vlax-release-object fldobj)
           ) ;_ end of progn
    ) ;_ end of if
  outval
  ) ;_ end of defun

Наличие закомментированных блоков кода лично я считаю не совсем правильным и нормальным. В процессе отладки – да, пожалуйста. Но как только функция “выпускается в свет”, подобные вещи лучше убирать. А если понадобится восстанавливать – добро пожаловать в системы контроля версий :)

Именование переменных
lisp’у (так же как и VB / VBA), в принципе, плевать на регистр символов в именах переменных или функций. Это не C / C++ / C#. Но я не стал бы использовать имена типа objFolder – достаточно выполнить форматирование кода при некоторых настройках, и имя станет objfolder или OBJFOLDER. Можете поверить – читать таким образом сформатированный код становится почти невозможно. Так что лучше разделять значимые элементы символами “-” или “_”.
У меня как-то сложилось, что в именах функций разделение идет символом “-“, параметры вызова тоже содержат “-“, а вот локальные переменные и функции, как правило, используют “_”.
С остальными элементами - локализацией переменных, обертыванием в обработчик ошибок запросов от пользователя - спорить не стану, поскольку не вижу никаких противоречий с собственным опытом :)



Поделитесь своим мнением


Я не робот.