Эта страница доступна также на следующих языках: English

## Скрипты Guile

В gEDA/gaf для обеспечения возможности написания скриптов на Scheme используется Guile Scheme, и в распоряжении разработчика оказываются все возможности языка Guile. Справочное руководство по Guile [Guile Reference Manual] можно найти либо в формате Info (`info guile` на большинстве систем), либо в формате HTML на веб-странице Guile.

Для доступа к объектам и страницам gEDA и для их изменения имеется набор модулей, называемый gEDA Scheme API. Есть и Справочное руководство по Scheme в gEDA [gEDA Scheme Reference Manual] в формате Info (`info geda-scheme`).

### Учебники

- Написание скриптов драйверов gnetlist на Scheme (John Doty)

Смотрите также раздел Расширение функциональности gschem Руководства пользователя gEDA gschem и раздел API драйвера в Scheme Руководства пользователя gEDA gnetlist.

### Справочная информация

- Примитивы Scheme для gnetlist
- Использование REPL в gschem

### Примеры скриптов

Каждый скрипт можно скачать и загрузить в gschem:

- нажмите `:` и введите

      (load "filename.scm")

- затем нажмите `Enter`

#### Удаление объектов с заданными свойствами

Например, удалим все объекты, являющиеся окружностями или дугами с нулевым радиусом

remove-objects.scm

      (use-modules (geda page))

      ; Проверяет, является ли объект OBJECT окружностью (circle)
      ; или дугой (arc) с нулевым радиусом
      (define (zero-radius-object? object)
        (or
          (and (circle? object) (= (circle-radius object) 0))
          (and (arc?    object) (= (arc-radius    object) 0))))

      (apply page-remove! (active-page)
             (filter
               zero-radius-object?
               (page-contents (active-page))))

Предположим, нам необходимо удалить компонент с известным атрибутом, тогда нам нужно также отделить и удалить все его атрибуты. Функция, определённая ниже делает именно это.

remove-components-with-attribs.scm

      (use-modules (geda page))
      (use-modules (geda object))
      (use-modules (geda attrib))

      ; Удаляет все компоненты, имеющие атрибут NAME=VALUE, со страницы PAGE
      (define (delete-components-by-attrib! page name value)
        (for-each
          (lambda (obj)
            (if (component? obj)
              (for-each
                (lambda (attr)
                  (and
                    (string=? (attrib-name attr) name)
                    (string=? (attrib-value attr) value)
                    (let ((attached-attribs (object-attribs obj)))
                      (apply detach-attribs! obj attached-attribs)
                      (apply page-remove! page obj attached-attribs))))
                (object-attribs obj))))
          (page-contents page)))

После загрузки файла, нажмите `:` и введите, например,

    (delete-components-by-attrib! (active-page) "refdes" "R1")

#### Процедуры для ввода/вывода

Следующий скрипт определяет две процедуры, которые могут использоваться в режиме пакетной обработки с помощью скриптов для gaf shell:

- `schematic-file->page`
- `page->schematic-file`

geda-io.scm

      (use-modules (ice-9 lineio))
      (use-modules (geda page))

      ; Процедуры ввода/вывода
      ; Читает файл FILE и выводит строку
      (define (file->string file)
        (let* ((port (make-line-buffering-input-port (open-file file "r"))))
          (do ((line "" (read-string port))
               (s "" (string-append s line)))
            ((eof-object? line) ; тест
             (close-port port)  ; выражение(я) для вычисления в конце
             s)                 ; возвращаемое значение
            ; empty body
            )))

      ; читает файл схемы FILE и возвращает объект страницы PAGE
      (define (schematic-file->page file)
          (string->page file (file->string file)))

      ; сохраняет страницу схемы PAGE в файл FILE
      (define (page->schematic-file page file)
        (with-output-to-file file
          (lambda () (display (page->string page)))))

#### Копирование, перемещение и вращение объектов

move-and-rotate.scm

       ; Scripting example by vzh per request of
      ; Kai-Martin Knaak :-)
      ; Use at your own risk.

      ; Основная процедура здесь
      ; multiple-copy-move-and-rotate-selection, что можно сократить до
      ; mcmars.
      ; Использование:
      ;   запустите gschem, чтобы там можно было использовать этот скрипт, например
      ;     gschem -s move-and-rotate.scm
      ;   выделите объекты в gschem, нажмите ':' (двоеточие) и наберите
      ;     (mcmars '(1000 . 500) 90 10)
      ;   нажмите <Enter>
      ; Наслаждайтесь!

      (use-modules (gschem selection))

      ; округление координат по ALIGN
      (define (ceiling-coords vector align)
        (cons
          (* (ceiling-quotient (car vector) align) align)
          (* (ceiling-quotient (cdr vector) align) align)
          ))

      ; Получение минимума X и минимума Y двух пар координат
      (define (min-coords coord1 coord2)
        (let ((x (min (car coord1) (car coord2)))
              (y (min (cdr coord1) (cdr coord2))))
          ; возвращаемое значение
          (cons x y)))

      ; Копирование, перемещение и вращение текущего выделения. Выделенные объекты
      ; сначала копируются, затем перемещаются на вектор VECTOR и, наконец, вращаются
      ; на угол ANGLE вокруг центра, который рассчитывается как округлённая до
      ; множителей 100 левая нижняя координата всех объектов в выделении.
      ; Если никакие объекты не выделены, открывает диалоговое окно сообщений gschem
      ; с предупреждением.
      ; Возвращает скопированные объекты.
      (define (copy-move-and-rotate-selection vector angle)
        (let ((objects (page-selection (active-page))))
          (if (null? objects)
            (gschem-msg "Select something first!")
            ; else
            (let* ((copied-objects (map copy-object objects))
                   (translated-objects (apply translate-objects! vector copied-objects))
                   (bounds (apply object-bounds translated-objects))
                   (rotation-center (ceiling-coords (min-coords (car bounds) (cdr bounds)) 100))
                   (rotated-objects (apply rotate-objects! rotation-center angle translated-objects)))
              (apply page-append! (active-page) rotated-objects)
              rotated-objects)
            )))

      ; Умножает VECTOR, который должен быть парой, на число NUMBER
      (define (multiply-vector-by vector number)
        (cons (* number (car vector)) (* number (cdr vector))))

      ; Копирование, перемещение и вращение текущего выделения количество
      ; раз, указанное аргументом NUMBER. Применяет процедуру
      ; copy-move-and-rotate-selection несколько раз, каждый раз увеличивая
      ; вектор и угол на заданные значения VECTOR и ANGLE.
      ; Если никакие объекты не выделены, открывает gschem message dialog with
      ; warning.
      ; Если никакие объекты не выделены, открывает диалоговое окно сообщений gschem
      ; с предупреждением.
      ; Возвращаемое значение не определено.
      (define (multiple-copy-move-and-rotate-selection vector angle num)
        (if (null? (page-selection (active-page)))
          (gschem-msg "Select something first!")
          ; else
          (do ((i num (1- i)))
            ((= i 0))
            (copy-move-and-rotate-selection
              (multiply-vector-by vector i) (* angle i)))
          ))

      ; Сокращение для имени процедуры multiple-copy-move-and-rotate-selection
      (define mcmars multiple-copy-move-and-rotate-selection)

#### Редактирование группы атрибутов

Допустим, вы выделили несколько позиционных обозначений (атрибут refdes) резисторов и хотите переименовать их все сразу, например, если они были скопированы из другого места.

set-selected-attribs-value

      (use-modules (gschem selection))

      (define (set-selected-attribs-value! value)
        (for-each
          (lambda (attrib)
            (set-attrib-value! attrib value))
          (page-selection (active-page))))

Использование процедуры в gschem:

    (set-selected-attribs-value! "R100.?")

Теперь, после изменения их номеров с помощью `T` `U`, вы копируете их все и хотите переименовать эти скопированные резисторы, добавив суффикс:

append-selected-attribs-suffix.scm

      (use-modules (gschem selection))

      (define (append-selected-attribs-suffix! suffix)
        (for-each
          (lambda (attrib)
            (set-attrib-value!
              attrib
              (string-append (attrib-value attrib) suffix)))
          (page-selection (active-page))))

Использование процедуры в gschem:

    (append-selected-attribs-suffix! "-top")

Теперь переименуем несколько других атрибутов, добавив префикс:

append-selected-attribs-prefix.scm

      (use-modules (gschem selection))

      (define (append-selected-attribs-prefix! prefix)
        (for-each
          (lambda (object)
            (and (attribute? object)
                 (set-attrib-value!
                   object
                   (string-append prefix (attrib-value object)))))
          (page-selection (active-page))))

Использование процедуры в gschem:

    (append-selected-attribs-prefix! "A1.")

Давайте заменим первые буквы выделенных атрибутов префиксом:

append-selected-attribs-prefix.scm

      (use-modules (gschem selection))

      (define (replace-selected-attribs-prefix! prefix)
        (for-each
          (lambda (object)
            (and (attribute? object)
                 (set-attrib-value!
                   object
                   (string-append
                     prefix
                     (string-copy (attrib-value object) 1)))))
          (page-selection (active-page))))

Использование процедуры в gschem:

    (replace-selected-attribs-prefix! "C")

Давайте переименуем выделенные атрибуты `netname=`, увеличив их значения на определённое число:

add-selected-attribs-number.scm

      (use-modules (gschem selection))

      (define (add-selected-attribs-number! number)
        (for-each
          (lambda (object)
            (and (attribute? object)
                 (set-attrib-value!
                   object
                   (number->string
                     (+ (string->number (attrib-value object)) number)))))
          (page-selection (active-page))))

Использование процедуры в gschem:

    (add-selected-attribs-number! 100)

Мы могли бы задать любую функцию вместо "+" для номера соединения в этой процедуре. Например:

use-another-func.scm

      (use-modules (gschem selection))

      (define (use-another-func! func)
        (for-each
          (lambda (object)
            (and (attribute? object)
                 (set-attrib-value!
                   object
                   (number->string
                     (func (string->number (attrib-value object)))))))
          (page-selection (active-page))))

Использование процедуры в gschem:

    (use-another-func! -)
    (define (multiply-by-2 x)
      (* 2 x))
    (use-another-func! multiply-by-2)