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

===== Скрипты Guile =====

В gEDA/gaf для обеспечения возможности написания скриптов на Scheme
используется [[http://www.gnu.org/s/guile/|Guile Scheme]], и в распоряжении
разработчика оказываются все возможности языка Guile. //Справочное
руководство по Guile// [//Guile Reference Manual//] можно найти либо в
формате Info (''[[info://guile|info guile]]'' на большинстве систем), либо в
формате HTML на
[[http://www.gnu.org/software/guile/docs/docs.html|веб-странице Guile]].

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

==== Учебники ====

  * [[gnetlist scheme tutorial.ru|Написание скриптов драйверов gnetlist на Scheme]] (//John Doty//)

Смотрите также раздел [[geda:gschem_ug:extensions.ru|Расширение
функциональности gschem]] //[[geda:gschem_ug.ru|Руководства пользователя
gEDA gschem]]// и раздел [[geda:gnetlist_ug.ru#API драйвера в Scheme]]
//[[geda:gnetlist_ug.ru|Руководства пользователя gEDA gnetlist]]//.

==== Справочная информация ====
  * [[geda>gEDA:gnetlist Scheme primitives|Примитивы Scheme для gnetlist]]
  * [[gEDA:gschem repl.ru|Использование REPL в gschem]]

==== Примеры скриптов ====
Каждый скрипт можно скачать и загрузить в **gschem**:
  * нажмите <key>:</key> и введите <code lisp>(load "filename.scm")</code>
  * затем нажмите <key>Enter</key>

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

<file lisp 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))))
</file>

Предположим, нам необходимо удалить компонент с известным атрибутом, тогда
нам нужно также отделить и удалить все его атрибуты.  Функция, определённая
ниже делает именно это.  <file lisp 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)))
</file>

После загрузки файла, нажмите <key>:</key> и введите, например, <code lisp>
(delete-components-by-attrib! (active-page) "refdes" "R1")  </code>

=== Процедуры для ввода/вывода ===
Следующий скрипт определяет две процедуры, которые могут использоваться
в режиме пакетной обработки с помощью скриптов для **gaf shell**:
  * ''schematic-file->page''
  * ''page->schematic-file''

<file lisp 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)))))
</file>


=== Копирование, перемещение и вращение объектов ===
<file lisp 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)  </file>


=== Редактирование группы атрибутов ===
Допустим, вы выделили несколько позиционных обозначений (атрибут refdes)
резисторов и хотите переименовать их все сразу, например, если они были
скопированы из другого места.  <file lisp 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))))
</file>

Использование процедуры в **gschem**: <code lisp>
(set-selected-attribs-value! "R100.?")  </code>

Теперь, после изменения их номеров с помощью <key>t</key> <key>u</key>, вы
копируете их все и хотите переименовать эти скопированные резисторы, добавив
суффикс: <file lisp 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))))
</file>

Использование процедуры в **gschem**: <code lisp>
(append-selected-attribs-suffix! "-top")  </code>

Теперь переименуем несколько других атрибутов, добавив префикс: <file lisp
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))))
</file>

Использование процедуры в **gschem**: <code lisp>
(append-selected-attribs-prefix! "A1.")  </code>

Давайте заменим первые буквы выделенных атрибутов префиксом: <file lisp
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))))
</file>

Использование процедуры в **gschem**: <code lisp>
(replace-selected-attribs-prefix! "C")  </code>

Давайте переименуем выделенные атрибуты ''netname='', увеличив их значения
на определённое число: <file lisp 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))))
</file>

Использование процедуры в **gschem**: <code lisp>
(add-selected-attribs-number! 100)  </code>

Мы могли бы задать любую функцию вместо "+" для номера соединения в этой
процедуре.  Например: <file lisp 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))))
</file>

Использование процедуры в **gschem**:
<code lisp>
(use-another-func! -)
(define (multiply-by-2 x)
  (* 2 x))
(use-another-func! multiply-by-2)
</code>
