Как импортировать другие файлы исходного кода в сценарии dm - PullRequest
2 голосов
/ 02 апреля 2020

Есть ли способ использовать несколько файлов кода в dm-скрипте для структурирования кода? Что-то вроде:

import "path/to/utility_functions.s";

utility_functions.do_something_general();

Обратите внимание, что я не хочу иметь код в качестве пункта меню, если это возможно. Код содержит только те функции, которые я использую в основном скрипте.


Я попробовал следующее:

Файл 1: test.s

void test(){
    result("test\n");
}

Файл 2: require-test.s

AddScriptFileToPackage("path/to/test.s", "test", 3, "test-function", "", "", 1);

ExecuteScriptString("test()"); // works immediately but feels wrong
test(); // works after restart

Теперь у меня есть следующие проблемы:

  • Я должен перезапустить DigitalMicrograph после выполнения этот скрипт, в противном случае test() не работает (ExecuteScriptString("test()"); работает, но неправильно использовать строки для вызова кода, если возможно, я бы хотел этого избежать)
  • Когда я перезапускаю DigitalMicrograph в другой раз AddScriptFileToPackage() sais 'Сценарий не может быть добавлен, поскольку пакет существует и доступен только для чтения. [...]». Есть ли способ обойти это или я должен использовать try блоков?

Я чувствую, что не делаю это неправильно в каком-то месте.

Ответы [ 3 ]

2 голосов
/ 02 апреля 2020
Сценарий

DM не поддерживает загрузку пакетов по требованию, но есть два различных способа достижения желаемого:

Использование пакетов библиотеки

Когда вы "устанавливаете" msgstr "скрипт, вы можете установить его как команду меню или как библиотеку. Это верно как для установки скриптов с помощью команды меню (которые хранятся в файле глобальных настроек), так и с помощью команды скриптов (которая может использоваться для создания файлов .gtk, которые затем можно добавлять / удалять из папки плагинов по мере необходимости. ).

Опция "menu" установит скрипт так, что он вызывается один раз через пункт меню, но не останется в памяти в противном случае.

Опция "library" выполнит сценарий один раз при запуске и держать сам сценарий в области видимости. Таким образом, вы можете определить методы (или классы) в файле библиотеки и сделать его общедоступным. И вы можете поместить некоторый исполняемый код в библиотеку, если вам нужно какое-то действие при запуске.

Использование библиотек сценариев в качестве плагинов .gtk, возможно, является рекомендуемым способом достижения того, чего вы хотите. Однако они всегда загружаются.

Совет: если вы создаете библиотеки, убедитесь, что вы используете очень уникальные имена классов и методов, чтобы избежать конфликтов. Я бы порекомендовал предварительно исправить все имена классов / методов с некоторым именем библиотеки, то есть использовать MyLib_MyClass вместо MyClass и т. П.

Уточнение: Сценарии, добавленные в виде библиотечных пакетов, постоянно добавляются в программное обеспечение, то есть эти пакеты создаются один раз и затем помещаются в папку плагинов. Они всегда будут загружаться при запуске DM и будут доступны. Метод пакета Library не подходит для временной «загрузки» внешних скриптов. Такой «импорт по требованию» не поддерживается сценариями DM.

Команды сценария для создания пакетов - это служебные команды, помогающие создавать пакеты простым и управляемым способом. Как правило, можно создать сценарий «Создать пакет XY» с несколькими такими командами, добавив все сценарии из расположения в пакет. Сценарий будет вызван один раз для создания файла пакета (впоследствии он уже находится в папке плагинов.) Только когда изменяются включенные сценарии и, следовательно, требуется обновить пакет, сценарий create-package вызывается снова. Обратите внимание, что в этом случае сначала необходимо удалить файл пакета из папки плагинов и запустить DigitalMicrograph без его загрузки, чтобы создать пакет new . В противном случае скрипт добавит к пакету, что было бы невозможно, если бы в пакете уже существовали методы с таким же именем.

Справочная документация F1 содержит пример скрипта: F1 help script example section GMS 3


Типичные примеры использования GMS 3.4.0 :

Скрипт хранится по адресу: C:\Tmp\testLib.s

void TestCall()
{
  Result("\nTest")
}

Скрипт хранится по адресу: C:\Tmp\menuAction.s

Result("\nPerforming an action here.")

Единовременный скрипт запуска для установки пакета:

// General package parameters
// *********************************************
string pkNa = "myPkg"       // Filename of plugin
number pkLe = 3             // level 3 (.gtk) only needed for load order
string pkLo = "user_plugin" // plugin location

string scriptRoot = "C:\\Temp\\"        

// List of Scripts to be installed as menu items
// *********************************************
// Each entry needs a (unique) command-name, a menu-name and an optional sub-menu name. 
// The "isLibary" flag is set to 0
// It is possible to add the same script multiple times. The script will be executed when the menu item
// is chosen. Methods and Classes of the script are not available otherwise
// A separator can be added by installing and empty script with a (unique) command name starting with "-"
AddScriptFileToPackage( scriptRoot + "menuAction.s", pkNa, pkLe, pkLo, "Call 1", "MyMenu", "MySubMenu", 0 ) 
AddScriptFileToPackage( scriptRoot + "menuAction.s", pkNa, pkLe, pkLo, "Call 2", "MyMenu", "", 0 ) 
AddScriptToPackage( "", pkNa, pkLe, pkLo, "-sep1", "MyMenu", "", 0 ) 
AddScriptFileToPackage( scriptRoot + "menuAction.s", pkNa, pkLe, pkLo, "Call 3", "MyMenu", "", 0 ) 

// List of Scripts to be installed as library 
// *********************************************
// Each entry needs a (unique) command-name. Menu-name and sub-menu name are "". 
// The "isLibary" flag is set to 1
// The script will be executed once on startup (if there is executable code). It is also executed once
// here during the install.
// Methods and Classes of the script are permanently available and need unique names.
// Adding a script to the package as libary can be used to create on-load-version info output.
AddScriptFileToPackage( scriptRoot + "testLib.s", pkNa, pkLe, pkLo, "library-1", "", "", 1 ) 
AddScriptToPackage( "Result(\"Script packages myPkg loaded.\\n\")", pkNa, pkLe, pkLo, "myPkg-versionInfo", "", "", 1 )

После запуска сценария установки там будет:

  • Подобное меню:
    Menu
  • Вывод в окно результатов, например:
    output
  • Файл пакета в папке C:\Users\USERNAME\AppData\Local\Gatan\Plugins\myPkg.gtk
  • Команда сценария TestCall() обычно доступна во всех сценариях.

Пакет будет загружаться каждый раз, когда DM запускается, пока файл .gtk остается в папке плагинов.

Вызов кода скрипта из скриптов

Язык сценариев supp Запускает две команды для вызова скрипта из скрипта:

  • Number ExecuteScriptString( String text )

  • Number ExecuteScriptFile( String file_path )

Использование команды для выполнения скриптов из dis c может делать то, что вы хотите, но поддержание полезной «библиотеки» таким образом может быть утомительным. Это также не позволяет вам устанавливать классы.


Пример вызова скрипта из скрипта:

// Direct example
void Demo()
{
    ClearResults()
    Result( "I am a test call.\n")
    number n = 5
    Result( "I am working on the number: " + n )
}
Demo()

//Having the script as a string
number otherNumber = 11 // To show how you can modify a script call as an example
string scriptStr
scriptStr += "void Demo()\n{" + "\n"
scriptStr += "ClearResults()" + "\n"
scriptStr += "Result( \"I am a test call.\\n\")" + "\n"
scriptStr += "number n = " + otherNumber + "\n"
scriptStr += "Result( \"I am working on the number: \" + n )"+ "\n"
scriptStr += "}\n"
scriptStr += "Demo()\n"

If ( TwoButtonDialog("Script-call","Show it", "Run it") )
{
    ClearResults()
    Result( scriptStr ) 
}
else
    ExecuteScriptString( scriptStr )
1 голос
/ 21 апреля 2020

Для всех, кому это нужно, я использую AddScriptFileToPackage() сейчас, вдохновленный @BmyGuest и @ MikeKundmann.

Следующее main.s всегда открыто в моей GMS. Настоящий код, над которым я работаю, находится в program.s. Для проверки вашего кода выполните main.s. Этот файл может быть выполнен несколько раз за один сеанс !

Для открытия GMS я использую (Windows) командный файл ниже. Это автоматически удаляет зарегистрированные плагины, что делает main.s пригодным для повторного использования. Для отладки я создал скрипт python, который объединяет все файлы, перечисленные в main.s. Таким образом, GMS переходит к ошибкам. Эта python программа может быть загружена с моей страницы github .

/**
 * File: main.s
 */

String __file__;
GetCurrentScriptSourceFilePath(__file__);
String __base__ = __file__.PathExtractDirectory(0);

/**
 * Load and add the file `filename`, the name will be the `filename` without
 * the extension.
 *
 * This is dynamic only for the current session. If GMS is restarted, using 
 * this will create errors except if the plugins folder does not contain the 
 * required files (delete `%LOCALAPPDATA%\Gatan\Plugins\` before starting).
 *
 * @param filename The filename (or path) relative to the path of this file
 * @param name The internal name to register the script with
 */
void require(String filename, String name){
    // AddScriptFileToPackage(
    //    <file_path>, 
    //    <packageName: filename of .gtk file in plugins>, 
    //    <packageLevel: load order [0..3]>,
    //    <command_name: id/name of the libary/command>,
    //    <menu_name: name of the menu, ignored if isLibrary=1>
    //    <sub_menu_name: name of the submenu, ignored if isLibrary=1>,
    //    <isLibrary: wheter to add as library (1) or as menu item (0)>
    // )
    AddScriptFileToPackage(__base__.PathConcatenate(filename), "__require_main_" + name, 3, name, "", "", 1);
}

/**
 * Require the file `filename` with the basename of the `filename` as the name.
 *
 * @see require(String filename, String name);
 *
 * @param filename The filename (or path) relative to the path of this file
 */
void require(String filename){
    require(filename, PathExtractBaseName(filename, 0));
}

void main(){
    // add libaries
    require("string-lib.s");

    // add main file
    require("program.s");
}

main();

(Windows) командный файл для запуска GMS. Это автоматически удаляет папку плагинов. Тогда main.s не вызывает никаких проблем.

@echo off

rem
rem File: start-gatan.bat
rem ---------------------

echo Deleting GMS cached libaries...

SET plugins_path=%LOCALAPPDATA%\Gatan\Plugins\
SET gms_path=%PROGRAMFILES%\Gatan\DigitalMicrograph.exe

if exist %plugins_path% (
    echo Deleting all .gtk files in %plugins_path%...
    del %plugins_path%__require_main_*.gtk /F /Q
    del %plugins_path%__require_main_*.gt1 /F /Q
    del %plugins_path%__require_main_*.gt2 /F /Q
    del %plugins_path%__require_main_*.gt3 /F /Q

    if exist "%gms_path%" (
        echo Starting GMS
        start "" "%gms_path%"
    ) else (
        echo GMS path %gms_path% does not exist.
        pause
    )
) else (
    echo Plugins path %plugins_path% does not exist.
    pause
)
1 голос
/ 08 апреля 2020

Следующий явный пример использования скрипта сборки может быть ближе к тому, что вы ищете. Это показывает, что в течение одного сеанса DM можно редактировать исходные файлы модуля и многократно перестраивать пакет без перезапуска DM, в отличие от пояснения о создании пакета, приведенного в ответе BmyGuest. В этом примере также используется очень удобная функция GetCurrentScriptSourceFilePath, которая значительно упрощает ссылки на пути к файлам, когда можно найти сценарий сборки и исходные файлы модуля в одной папке (этот подход я использую в своих собственных проектах разработки).

Вот расположение моих файлов для этого примера:

enter image description here

Два исходных модуля - очень простые библиотеки функций и классов.

Вот модуль1:

    void Module1SayHello()
    {
        OKDialog("Hello from module 1");
    }

А вот модуль2:

    class Module2TestClass
    {
        void Module2SayHello(Object self)
        {
            OKDialog("Hello from module 2");
        }
    }

Вот скрипт сборки:

    void main()
    {
        // Establish the source code directory relative to the current build script location
        String buildScriptSourceFilePath;
        GetCurrentScriptSourceFilePath(buildScriptSourceFilePath);
        String sourceFileDir = buildScriptSourceFilePath.PathExtractDirectory(0);

        // Add the modules
        AddScriptFileToPackage(sourceFileDir.PathConcatenate("Module1.s"), "MultiModuleTest", 3, "Module1", "", "", 1);
        AddScriptFileToPackage(sourceFileDir.PathConcatenate("Module2.s"), "MultiModuleTest", 3, "Module2", "", "", 1);
    }

    main();

В отличие от вышеупомянутого поясним, что этот сценарий сборки может запускаться несколько раз в течение сеанса DM, а содержимое файла пакета заменяется каждый раз. Так что теперь у вас есть очень хорошая среда разработки, где вы можете открыть исходный файл для модуля, отредактировать его по своему желанию, сохранить его, а затем пересобрать файл пакета. Можно использовать следующий тестовый сценарий, чтобы увидеть, что поведение изменяется при редактировании, сохранении и перестройке реализации любой функции или метода в исходных файлах модуля:

    void main()
    {
        Module1SayHello();
        Alloc(Module2TestClass).Module2SayHello();
    }

    main();

Из-за способа, которым сценарий DM интерпретатор анализирует, маркирует и выполняет код, все функции и методы, вызываемые в любом месте сценария, должны быть предварительно определены до выполнения сценария. Вот почему вышеприведенный тестовый скрипт или любой другой скрипт, использующий добавленные модули, нельзя просто добавить в конец скрипта сборки (за исключением случаев, когда он встроен в строку, переданную в функцию ExecuteScriptString, как указано в поставленном вопросе) , Поэтому концепция импортированных модулей кода (например, как в Python) в сценариях DM не представляется возможной (как указано в комментарии к ответу BmyGuest). В этом смысле сценарии DM показывают свои корни в концепциях кодирования 1990-х годов, которые обычно включали отдельные фазы компиляции, компоновки и выполнения.

Тем не менее, описанный здесь подход сценария сборки позволяет воспользоваться преимуществами истинно интегрированная среда разработки (IDE). Например, можно добавить исходные файлы модуля (и сценарий сборки) в проект в Visual Studio и получить все преимущества современного редактора многофайлового кода и контроля версий (например, через Git). Это то, что я делаю с платформой Enabler.

Единственное предостережение в том, что после закрытия сессии DM файл плагина (пакета) каким-то образом завершается, и его больше нельзя заменить. по сценарию сборки в будущем сеансе DM. В этом случае необходимо удалить файл пакета из папки плагинов перед возобновлением другого сеанса разработки в DM (как описано в пояснении из BmyGuest).

...