Советы скриптописцам

Опыт. Наблюдения. Особенности. Глюки. Недокументированные возможности


Нестандартное применение списков команд

Список команд (command list) можно использовать не только по прямому назначению. По сути дела, список команд - многомерный массив, ведь в строке-команде можно хранить кучу информации! Например, функция cl.AddLeft имеет четыре аргумента (команда, параметры, рабочая директория, способ запуска), где можно упорядоченно хранить данные и извлекать их поодиночке. А как вам возможность добавить туда любое количество команд, каждая со своими аргументами? Более того, список можно даже сохранить в pcf-файл!

Налицо очевидные преимущества перед использованием плагинов vec и map. Во-первых, они загружаются отдельно и, строго говоря, нуждаются в выгрузке, а список команд всегда "под рукой". Во-вторых, нет проблем с передачей списка в качестве параметра другому скрипту. В-третьих, вектора и "карты" одномерны, в отличие от списка.

Есть и недостатки. Главное - в списках отсутствуют возможности сортировки. Кроме того, не дай Бог случайно запустить на выполнение команду, которая совсем для этого не предназначалась! Однако последнее весьма маловероятно. Что же касется сортировки, то, если она понадобится, можно скопировать данные из списка в вектор, отсортировать, скопировать обратно и удалить вектор.


Что делать, если ничего не получается?

Бывает, что скрипт, по всем признакам долженствующий работать, выдает ошибку. В 90% случаев дело в неправильной оценке "долженствования" и причина неработоспособности - ошибка программиста. Но если "проверка глазами" и отладочная печать вновь и вновь показывают безошибочность кода, можно попробовать иерархически выполнить следующие действия:

  1. Перезапуск PowerPro;
  2. Перезапуск Total Commander;
  3. Перезапуск Windows.
У меня был всего один или от силы два случая, когда дело дошло до третьего шага, но это было. Чем глубже скрипт проникает в недра системы, тем больше вероятность вызвать ее неадекватное поведение. Хотя почти всегда помогает первое действие - закрыть и вновь открыть PowerPro. Характерный признак глюка PowerPro - при незначительных изменениях кода выдается сообщение о совсем другой ошибке.

Особенно много глюков, судя по всему, содержится в плагине vec. Чаще всего программа жалуется на выходящий за пределы индекс. В этих случаях перезагрузка PowerPro почти всегда ошибку устраняет.

И, наконец, нередко появление глюка наблюдается при следующей последовательности событий:

Запуск скрипта -> сообщение об ошибке -> обнаружение и исправление ошибки -> запуск скрипта -> сообщение о другой ошибке

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

А однажды случилось так, что ни многократные перезагрузки, ни чистка реестра, ни переустановка обеих программ (Total Commander и PowerPro) не помогли - Total Commander почти на любое действие отвечал сообщением "File not found". Если такое случилось, попробуйте запустить из Total Commander любую внешнюю программу, заведомо исправно работающую. Если сообщение об ошибке вылезает вновь, перезагрузкой или даже переустановкой программы не обойтись. Я похвалил себя, что регулярно делал копии реестра из резервной операционки - иначе пришлось бы переустанавливать Windows.


Осторожно - глобальные переменные!

Простенькая команда

win.debug(allglobals)

позволит узнать много интересного о скрипте и сэкономить память.

Напомню, что по умолчанию всякая переменная в PowerPro является глобальной, что, вообще говоря, неразумно. Забыв описать некую переменную как локальную, мы впустую расходуем память, но это лишь полбеды. Гораздо хуже, если в другом скрипте вы будет использовать совершенно другую по смыслу переменную с тем же именем! Конечно, ситуация маловероятная, но тем труднее будет найти ошибку, если она произойдет! Короче говоря:

  1. Объявляйте все переменные как local
  2. … но изменяйте спецификатор на global, только твердо осознавая, зачем вы это делаете;
  3. Вывод: никогда не используйте переменные без спецификатора доступа.
Мне укажут, что есть специальная установка: "Setup\Advanced setup\Other\Variables must be declared before using". Однако по умолчанию этот флаг сброшен. Если пользователь по какой-то причине установил данный флаг, то третий совет к нему не относится.


Надо просто немного подождать…

Только-только начиная осваивать премудрости скриптинга, я иногда доходил до бешенства - простейшие команды либо не работали, либо, что было еще загадочнее, работали через раз. Вскоре я понял причину и с тех пор проблем у меня стало гораздо меньше.

Дело в том, что все, абсолютно все операции, которые, на взгляд пользователя, выполняются мгновенно, требуют пусть и малого, но все-таки конечного времени. Открытие/закрытие окна/файла, чтение/запись файла, посылка сообщений окну, даже занесение значения в оперативную память - все требует времени для выполнения, хоть оно и исчисляется миллисекундами. Одна из моих ошибок на первых порах состояла в том, что я выдавал команды подряд, без паузы. В результате иногда первая команда успевала выполниться к моменту выполнения второй, а иногда нет, что и порождало загадочные непостоянные сбои.

Не зря Bruce Switzer такое внимание уделяет команде wait и снабжает ее столь многочисленными модификациями. Однозначных рекомендаций, к сожалению, здесь дать не может даже он. Конкретное время зависит от тысячи причин - операционной системы, аппаратного обеспечения, загруженности памяти в момент выполнения скрипта, резидентных программ и многого другого. Так что постараюсь сформулировать лишь самые общие советы тем, кто пишет свои скрипты (причем не обязательно на языке PowerPro):

Копирование векторов

Здесья почти дословно воспроизвожу свою переписку с автором PowerPro, начатую этим моим сообщением.

Создадим простой скрипт:


local v = vec.createfromwords("1 2")
local w = v
v[0] = 5
win.debug(w[0])
quit

В окно отладки выводится "5". Но это кажется странным: мы создали вектор, затем присвоили его значение (а следовательно, все элементы) другому вектору, а затем изменили один элемент первого. Поскольку это изменение произошло после присваивания значения первого вектора второму оно, следовательно, не должно влиять на первый, так? Оказалось, не так.

Проверим на подобном скрипте, но оперирующем с обычными переменными:


local v = 1
local w = v
v = 5
win.debug(w)
quit

Результат будет "1", что полностью соответствует ожиданиям.

Автор ответил, что оператор присваивания вида


a = b

где обе переменные объявлены как вектора, присваивает второму (b) не элементы, а ссылку на область памяти ("указатель" - pointer - в терминах С++), содержащую элементы первого вектора (a). Таким образом, любые операции над вектором a автоматически применяются к вектору a.

На мой взгляд, это нелогично. Зачем иметь две идентичные копии одного и того же вектора? Но даже если это поведение и логично, оно должно быть описано в документации. Программист на С++, располагая и переменной, и указателем на нее, сам решает, когда присваивать переменную, а когда – ссылку: поведение программы в общем случае будет другим. В PowerPro нет понятия указателя, и поведение операторов, присваивающих именно указатель, надо оговаривать особо.

Автор пообещал добавить к плагину vec функцию, копирующему во второй вектор именно элементы первого, без необходимости организации цикла, как это происходит сейчас.


На главную