//Translations of this page are also available in the following languages:// [[guile_scripting.ru|Русский]]. ===== Guile scripting ===== gEDA/gaf uses [[http://www.gnu.org/s/guile/|Guile Scheme]] to provide Scheme scripting capabilities, and all of the features of Guile are available to use. The //Guile Reference Manual// is available as an Info manual (''[[info://guile|info guile]]'' on most systems), or [[http://www.gnu.org/software/guile/docs/docs.html|on the Guile website]]. A collection of modules is provided for accessing and modifying gEDA objects and pages, called the gEDA Scheme API. The //gEDA Scheme Reference Manual// is also available as an Info manual (''[[info://geda-scheme|info geda-scheme]]''). ==== Tutorials ==== * [[gnetlist scheme tutorial|Scripting a gnetlist backend in scheme]] (John Doty) See also the [[geda:gschem_ug:extensions|Extending gschem]] section of the //[[geda:gschem_ug|gEDA gschem User Guide]]//, and [[geda:gnetlist_ug#scheme_backend_api|Scheme Backend API]] section of the //[[geda:gnetlist_ug|gEDA gnetlist User Guide]]//. ==== Reference documents ==== * [[gnetlist Scheme primitives]] * [[gschem repl|Using REPL in gschem]] ==== Scripting examples ==== You can download each script example and load it in **gschem**: * just hit : and enter (load "filename.scm") * then hit Enter You can install them as well if you don't want to load them every time: * copy the script you want into your //''~/.gEDA''// directory * put the line (load "filename.scm") into your //''~/.gEDA/gschemrc''// (replace //filename.scm// with the real name of the script) === Removing objects with specific properties === For instance, let's remove all objects which are circles or arcs with zero radius: (use-modules (geda page)) ; Checks if the OBJECT is a circle or an arc with zero radius (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)))) Let's suppose we have a component with a known attribute to remove, then we have to detach and remove all its attributes, too. The function below does exactly this. (use-modules (geda page)) (use-modules (geda object)) (use-modules (geda attrib)) ; Removes all components having the attrib NAME=VALUE from 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))) After loading the file, hit : and enter, for example, (delete-components-by-attrib! (active-page) "refdes" "R1") === Procedures for input-output === The following script defines two procedures that can be used in **gaf shell** batch scripts: * ''schematic-file->page'' * ''page->schematic-file'' (use-modules (ice-9 lineio)) (use-modules (geda page)) ; Input/output procedures ; reads FILE and outputs string (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) ; test (close-port port) ; expression(s) to evaluate in the end s) ; return value ; empty body ))) ; reads schematic FILE and outputs PAGE object (define (schematic-file->page file) (string->page file (file->string file))) ; saves schematic PAGE to FILE (define (page->schematic-file page file) (with-output-to-file file (lambda () (display (page->string page))))) === Copy, move, and rotate objects === ; Scripting example by vzh per request of Kai-Martin Knaak :-) ; Use at your own risk. ; The main procedure here is ; multiple-copy-move-and-rotate-selection which can be abbreviated ; as mcmars. ; Usage: ; launch gschem so it can use this script, e.g. ; gschem -s move-and-rotate.scm ; select objects in gschem, then hit ':' (semicolon) and type ; (mcmars '(1000 . 500) 90 10) ; hit ; Enjoy! (use-modules (gschem selection)) ; align coords by ALIGN (define (ceiling-coords vector align) (cons (* (ceiling-quotient (car vector) align) align) (* (ceiling-quotient (cdr vector) align) align) )) ; Get minimum X and minimum Y of two pairs of coords (define (min-coords coord1 coord2) (let ((x (min (car coord1) (car coord2))) (y (min (cdr coord1) (cdr coord2)))) ; return value (cons x y))) ; Copy, move and rotate current selection. The selected objects ; are first copied, then translated by VECTOR and finally rotated ; by ANGLE about center which is calculated as rounded by 100 ; lower left coordinate of all objects in selection. ; If no objects are selected, opens gschem message dialog with ; warning. ; Returns the copied objects. (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) ))) ; Multiply VECTOR which must be a pair by NUMBER (define (multiply-vector-by vector number) (cons (* number (car vector)) (* number (cdr vector)))) ; Copy, move and rotate current selection NUMBER times. Applies ; the copy-move-and-rotate-selection procedure multiple times ; increasing every time vector and angle by given values of VECTOR ; and ANGLE. ; If no objects are selected, opens gschem message dialog with ; warning. ; Return value is unspecified. (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))) )) ; Abbreviated name for the multiple-copy-move-and-rotate-selection ; procedure (define mcmars multiple-copy-move-and-rotate-selection) === Group attribute editing === Let's suppose you have selected several resistors' refdeses and want to rename them at once, e.g., if they were copy from another place. (use-modules (gschem selection)) (define (set-selected-attribs-value! value) (for-each (lambda (attrib) (set-attrib-value! attrib value)) (page-selection (active-page)))) Usage of the procedure in **gschem**: (set-selected-attribs-value! "R100.?") Now, after renumbering them using t u, you copy them all and want to rename those copied resistors appending a suffix: (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)))) Usage of the procedure in **gschem**: (append-selected-attribs-suffix! "-top") Now, let's rename some other attributes by adding a prefix: (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)))) Usage of the procedure in **gschem**: (append-selected-attribs-prefix! "A1.") Let's replace first letters of selected attribs with prefix: (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)))) Usage of the procedure in **gschem**: (replace-selected-attribs-prefix! "C") Let's rename selected ''netname='' attributes increasing them by a fixed number: (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)))) Usage of the procedure in **gschem**: (add-selected-attribs-number! 100) We could set any function instead of "+" on the net number in this procedure. For instance: (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)))) Usage of the procedure in **gschem**: (use-another-func! -) (define (multiply-by-2 x) (* 2 x)) (use-another-func! multiply-by-2) === Moving objects using arrows === Let's define actions to move selected objects using Shift + arrow keys. (use-modules (gschem selection)) ; Default offset to move (define offset 100) ; Get moving vector (define (move-selection direction) (apply translate-objects! (case direction ((left ) (cons (- offset) 0)) ((right) (cons (+ offset) 0)) ((down ) (cons 0 (- offset))) ((up ) (cons 0 (+ offset))) (else #f)) (page-selection (active-page)))) ; Define actions (define (&move-selection-left ) (move-selection 'left )) (define (&move-selection-right) (move-selection 'right)) (define (&move-selection-down ) (move-selection 'down )) (define (&move-selection-up ) (move-selection 'up )) ; Define shortcuts (global-set-key "Left" '&move-selection-left) (global-set-key "Right" '&move-selection-right) (global-set-key "Up" '&move-selection-up) (global-set-key "Down" '&move-selection-down) The following script redefines current shortcuts so that if nothing is selected the canvas is moved with arrow keys (without Shift in this case), otherwise selected objects are moved. (use-modules (gschem selection)) ; Default offset to move (define offset 100) ; Get moving vector (define (move-selection direction) (let ((selection (page-selection (active-page)))) (if (null? selection) ; default behaviour (case direction ((left ) (&view-pan-left)) ((right) (&view-pan-right)) ((down ) (&view-pan-down)) ((up ) (&view-pan-up)) (else #f)) ; modified behaviour (apply translate-objects! (case direction ((left ) (cons (- offset) 0)) ((right) (cons (+ offset) 0)) ((down ) (cons 0 (- offset))) ((up ) (cons 0 (+ offset))) (else #f)) (page-selection (active-page)))) )) ; Define actions (define (&move-selection-left ) (move-selection 'left )) (define (&move-selection-right) (move-selection 'right)) (define (&move-selection-down ) (move-selection 'down )) (define (&move-selection-up ) (move-selection 'up )) ; Define shortcuts (global-set-key "Left" '&move-selection-left) (global-set-key "Right" '&move-selection-right) (global-set-key "Up" '&move-selection-up) (global-set-key "Down" '&move-selection-down)