AutoLISP
AutoLISP is a dialect of the LISP programming language developed by Autodesk specifically for extending and customizing the functionality of AutoCAD software.[1] Introduced in AutoCAD Release 2.1 in the mid-1980s, it was chosen as the initial API due to LISP's suitability for handling unstructured design processes, allowing users to iteratively test and refine solutions.[1] Over the decades, AutoLISP has become the standard tool for automating repetitive tasks, manipulating drawing entities, and interacting with AutoCAD's environment variables and commands.[2]
Key features of AutoLISP include support for expressions, functions, variables, and data types such as integers, real numbers, strings, and lists, enabling efficient handling of geometric calculations and system interactions.[3] It integrates with Microsoft ActiveX Automation interfaces on Windows platforms, providing enhanced access to AutoCAD objects, though this is limited in AutoCAD LT and unavailable on Mac OS.[2] Programs are typically written in simple ASCII text files using editors like Notepad or TextEdit, and can be compiled into formats such as Fast-load AutoLISP (FAS) files for optimized performance.[3]
AutoLISP development is further supported by Visual LISP, an integrated development environment (IDE) available exclusively in full AutoCAD for Windows, which facilitates source code creation, editing, testing, and debugging.[1] Alternatively, the AutoLISP Extension for Microsoft Visual Studio Code enables cross-platform development on both Windows and Mac OS.[2] Starting with AutoCAD LT 2024, AutoLISP support has been added, enabling loading and running of custom routines in LT versions including 2025, making it accessible for a broader range of users in CAD automation and customization workflows.[4]
Introduction
Definition and Purpose
AutoLISP is a dialect of the Lisp programming language, tailored specifically for Autodesk's AutoCAD software to enable customization and automation of computer-aided design (CAD) processes. Introduced in AutoCAD Release 2.1 in the mid-1980s, and formally named in Release 2.18 in January 1986, it serves as an embedded scripting language that allows users to extend AutoCAD's capabilities directly within the application.[1][3]
The primary purposes of AutoLISP include customizing AutoCAD workflows by creating user-defined commands and automating repetitive tasks, such as object selection and data entry at the command line.[5] It also facilitates the development of functions for geometric calculations, providing tools to compute distances, angles, and other spatial properties essential for design tasks.[6] Additionally, AutoLISP supports the integration of external data into drawings through mechanisms like extended data (xdata), which can link entity information to records in external databases or files.[7]
A key unique aspect of AutoLISP is its interpretive nature, which permits real-time execution of code without compilation, allowing scripts to be entered and tested directly at the AutoCAD command line during active sessions.[8] This immediacy makes it particularly suited for iterative development and on-the-fly adjustments in CAD environments.[8]
Relation to the Lisp Family
AutoLISP is derived from an early version of XLISP, a compact implementation of Common Lisp developed by David Betz for personal computers in the 1980s.[9] XLISP itself aimed to provide a lightweight subset of Common Lisp's features, emphasizing portability and simplicity over the full generality of the standard. Autodesk adapted this foundation for AutoLISP to create a scripting language tailored for AutoCAD, introducing it in Release 2.1 in the mid-1980s and formally naming it in version 2.18 in January 1986.[1]
To prioritize efficiency in CAD environments, AutoLISP omits many advanced Lisp capabilities present in Common Lisp, such as user-defined macros via defmacro and object-oriented programming extensions like CLOS.[10] This streamlining results in a leaner language suitable for rapid scripting of drawing manipulations, while retaining core syntactic elements like prefix notation—for instance, the expression (+ 1 2) evaluates to 3, mirroring Lisp's functional style.[1] Additionally, AutoLISP lacks a package system for namespace management, relying instead on a single global namespace, and offers limited visibility into garbage collection processes, with only a basic gc function for manual invocation rather than sophisticated control.[11]
Unlike Common Lisp's emphasis on general-purpose computing, AutoLISP optimizes string and symbol handling for AutoCAD-specific tasks, such as managing entity names as strings in the drawing database.[12] It inherits Lisp's homoiconicity, where code is represented as data structures (lists), facilitating dynamic function creation and evaluation within AutoCAD sessions—for example, using defun to define functions at runtime and eval to execute list-based expressions.[2] This property supports flexible automation of design workflows without requiring compilation.
History
Origins and Early Development
AutoLISP was developed by Autodesk in the mid-1980s as a dialect of the Lisp programming language, specifically adapted from an early version of XLISP created by David Betz, to provide advanced customization capabilities for AutoCAD users. Engineers at Autodesk, including key contributors like John Walker and Duff Kurland, recognized the need for a more powerful scripting mechanism amid growing user demands for extending the software's functionality beyond simple menu macros and shape files, which were limited in handling complex, repetitive tasks. This adaptation aimed to embed a Lisp interpreter directly into AutoCAD's runtime environment, allowing for dynamic, programmable interactions with the drawing database.[13][1]
The language was first introduced in January 1986, with AutoCAD Release 2.18 for the MS-DOS operating system, marking the debut of Lisp-based scripting as a core feature and enabling users to write custom functions for automating design processes. Prior to this, customization relied heavily on rudimentary tools like menu systems, which supported only linear command sequences, and shape files, which were restricted to predefined geometric forms without procedural logic. AutoLISP addressed these shortcomings by facilitating procedural geometry generation, where scripts could dynamically create and manipulate entities based on variables and conditions, thus supporting iterative design workflows in engineering and architecture. This initial implementation built on a precursor "variables and expressions" feature from Release 2.1 in May 1985, but Release 2.18 provided the full interpreter for comprehensive scripting.[13][14]
Early development faced significant challenges, particularly in embedding the Lisp interpreter into AutoCAD's C-based runtime, which required careful optimization to avoid performance overhead and maintain stability on resource-constrained 1980s-era PCs. These hurdles were overcome through iterative testing and refinements, laying the foundation for AutoLISP's role as AutoCAD's primary extension language.[13]
Evolution and Key Milestones
Following its initial introduction in 1986 with AutoCAD Release 2.18, AutoLISP underwent significant expansions during the 1990s to align with AutoCAD's growing capabilities in 3D modeling and system performance. In AutoCAD Release 12 (1992), AutoLISP gained enhanced support for 3D entities, enabling programmatic manipulation of advanced modeling features such as regions and solids through the integration with the Advanced Modeling Extension (AME) R2.1.[15] These updates marked a shift toward more robust automation for complex architectural and engineering designs.
The 2000s brought further milestones that modernized AutoLISP's development environment and interoperability. AutoCAD Release 14 (1997) incorporated ActiveX integration, exposing AutoCAD objects and methods to external applications via Microsoft's ActiveX Automation interface, which AutoLISP could leverage for cross-platform scripting and enhanced object manipulation.[16] Building on this, Visual LISP was introduced as an IDE extension in AutoCAD 2000 (1999), providing a graphical editor, debugger, and compiler that extended AutoLISP's capabilities to access the full AutoCAD object model, replacing earlier text-based editing limitations. These enhancements revolutionized custom application development by facilitating object-oriented programming and seamless integration with Windows APIs.
In the 2010s and 2020s, AutoLISP evolved to support cloud-based workflows while maintaining its core status amid emerging alternatives. AutoCAD 2016 introduced cloud compatibility features, including digital signing for AutoLISP files, ensuring secure loading and execution in cloud environments like AutoCAD 360 without compatibility warnings.[17] AutoLISP remained a retained core language, with backward compatibility preserved for existing routines.[18] In 2020, Autodesk announced the retirement of the Visual LISP IDE, with plans for removal in a future release, though it remains available as of AutoCAD 2025. A milestone in modern tooling occurred with enhancements to the AutoLISP Extension for Visual Studio Code in 2023, providing improved IDE support including syntax highlighting, debugging, and project management for cross-platform development, fully integrated as of AutoCAD 2025.[19]
Language Fundamentals
Syntax and Data Types
AutoLISP employs prefix notation for all expressions, where the function or operator name precedes its arguments within parentheses, forming S-expressions that represent both code and data structures.[20] For instance, the expression (+ (* 2 3) 4) nests multiplication inside addition, evaluating to 10 by first computing the product (6) and then adding 4.[20] This notation allows arbitrary nesting of forms, enabling complex computations without infix operators or precedence rules beyond left-to-right evaluation of arguments before applying the outermost function.[20]
The fundamental data types in AutoLISP are atoms and lists, with atoms serving as indivisible units and lists as compound structures. Atoms include integers (whole numbers like 42), reals (floating-point numbers like 3.14), strings (text sequences enclosed in double quotes, such as "Hello"), and symbols (identifiers like variable names or function names, e.g., x or +).[21] Lists are ordered collections of atoms or sublists delimited by parentheses, such as (1 2 3), and can be quoted with a leading apostrophe ('(1 2 3)) to treat them as literal data rather than executable code.[21] AutoLISP also features specialized types tailored to CAD environments, including entity names (opaque references to drawing objects, printed as <Entity name: 7ff6a0b0>), and selection sets (collections of entities selected by the user or program).[21]
Evaluation in AutoLISP occurs automatically for non-quoted forms, recursively processing inner expressions first until atoms are reached, with the special atom nil representing both logical false and the empty list ().[21] The quote operator (') or the quote function suppresses this evaluation, preserving the form as data; for example, (+ 1 2) yields 3, while '(+ 1 2) returns the unevaluated list (+ 1 2).[21] In conditional contexts, any non-nil value is treated as true.[21]
Type conversions are essential for interfacing with AutoCAD's string-based inputs and outputs, facilitated by functions like atoi, rtos, and princ. The atoi function converts a string to an integer, such as (atoi "123") returning 123, enabling numeric processing of textual data.[22] Conversely, rtos formats a real number as a string according to specified mode and precision, e.g., (rtos 123.456 2 2) produces "123.46" in decimal mode with two decimal places, respecting system variables like LUNITS.[22] The princ function outputs expressions to the command line or console without adding quotes or newlines, aiding in displaying converted values, as in (princ "Value: ") followed by a stringified number.[22]
Built-in Functions and Operators
AutoLISP includes a core set of built-in functions and operators that enable basic computations, data structure manipulations, and user interactions, forming the foundation for scripting within AutoCAD environments. These functions operate on standard data types such as integers, reals, lists, and strings, supporting efficient processing of geometric and textual data relevant to computer-aided design.[23]
Arithmetic operators in AutoLISP handle numerical operations on integers and real numbers, facilitating calculations like distances and coordinates in drawings. The addition operator + sums one or more numbers, as in (+), which returns 0, or (+ 5 3.2), yielding 8.2. Subtraction with - computes the difference between two numbers, such as (- 10 4.5) resulting in 5.5. Multiplication via * multiplies numbers, for example (* 2 3.14) produces 6.28. Division using / divides the first number by subsequent ones, like (/ 10 2) giving 5.0. The remainder function rem returns the integer remainder of division for integers, such as (rem 10 3) returning 1. These operators support variable arguments and promote type coercion between integers and reals for seamless CAD computations.[24]
List manipulation functions allow construction, querying, and modification of lists, which are central to representing drawing entities and selections in AutoLISP. The car function extracts the first element from a list, for instance (car '(1 2 3)) returns 1. Conversely, cdr retrieves the rest of the list excluding the first element, so (cdr '(1 2 3)) yields (2 3). The cons function builds a new list by prepending an element to an existing list, as demonstrated by (cons 1 '(2 3)) producing (1 2 3). To combine multiple lists, append concatenates them, such as (append '(1 2) '(3 4)) resulting in (1 2 3 4). The reverse function inverts the order of list elements, for example (reverse '(1 2 3)) returns (3 2 1). These functions enable dynamic assembly and traversal of hierarchical data structures typical in CAD workflows.[25]
String and input/output functions support text processing and user communication, essential for prompts, labels, and file interactions in AutoCAD scripts. The strcat function concatenates two or more strings, like (strcat "Point " "A") producing "Point A". For extraction, substr retrieves a substring starting from a specified position, optionally up to a given length, such as (substr "Hello [World](/page/World)" 7 5) returning "World". User input is captured via getstring, which prompts for a string response and optionally allows spaces if the first argument is T, for example (getstring T "\nEnter name: ") waits for keyboard input. Output to the command line or screen uses princ, which prints an expression without quoting, as in (princ "Hello") displaying Hello without a trailing newline. These functions streamline text-based interactions without advanced formatting libraries.[26]
Mathematical functions in AutoLISP provide essential trigonometric and algebraic operations, primarily for 2D and 3D geometric calculations in CAD contexts, without support for higher-level libraries. The sin function computes the sine of an angle in radians, such as (sin 1.5708) approximating 1.0 for π/2. Similarly, cos returns the cosine, with (cos 0) yielding 1.0. The sqrt function calculates the square root of a non-negative number, for instance (sqrt 16) returning 4.0. Exponential growth is handled by exp, which raises e to the power of the input, like (exp 1) producing approximately 2.718. These are limited to scalar computations suited for vector math in drawings, such as angle resolutions or scaling factors.[24]
Integration with AutoCAD
Command and Entity Interaction
AutoLISP enables programmatic execution of AutoCAD commands through the command function, which sends arguments to AutoCAD in response to successive prompts, allowing scripts to automate drawing operations. The function accepts strings for command names and options, lists for points, and an empty string ("") to simulate Enter, thereby invoking commands like LINE to create entities between specified points. For instance, the expression (command "._line" '(1 1) '(1 5) "") draws a vertical line from (1,1) to (1,5) in the current drawing.[27] This mechanism ensures that AutoLISP routines can replicate manual command-line interactions while passing evaluated data types such as integers, reals, or point lists.[27]
Entity selection in AutoLISP is facilitated by the ssget function, which creates a selection set (pickset) from objects based on methods like "ALL" for all entities, window selections, or filters for specific types. The syntax (ssget [sel-method] [pt1 [pt2]] [pt-list] [filter-list]) supports interactive prompting if no arguments are provided, or programmatic filtering, such as (ssget "_C" '(0 0) '(1 1)) for a crossing window selection.[28] Return values are valid selection sets or nil if empty, with a limit of 128 open sets per session.[28] Complementing this, the entlast function retrieves the entity name of the most recently created or modified non-deleted main object, often used post-command to reference newly added entities, as in (setq e1 (entlast)) yielding <Entity name: 2c90538>.[29] It returns nil for empty drawings and ignores subentities or deleted objects.[29]
Point and vector handling supports interactive and calculated inputs essential for geometric operations. The getpoint function pauses for user specification of a point, returning a 3D list in the current UCS, with optional base point for rubber-banding, as in (getpoint '(1.5 2.0) "Second point: ").[30] Similarly, getangle solicits an angle in radians from a base point or the origin, measuring counterclockwise from the ANGBASE direction, exemplified by (getangle '(1.0 3.5) "Which way? ").[31] For computations, the polar function derives a point at a given angle and distance from a base, using (polar pt ang dist) to yield UCS coordinates independent of the construction plane, such as (polar '(1 1) 0.785398 1.414214) returning (2.0 2.0).[32] These functions blend user input with programmatic precision, avoiding direct expressions in responses.[30][31]
User interaction primitives like getstring and getint facilitate prompt-based input, integrating seamlessly with command flows. The getstring function requests a string, optionally allowing spaces with a true flag, and handles backslashes by doubling them, as in (getstring T "Enter [filename](/page/Filename): ") capturing paths up to 132 characters.[33] It returns nil on empty Enter and rejects expressions.[33] The getint function similarly prompts for integers within -32,768 to 32,767, re-prompting on invalid entries like decimals with "Requires an integer value," via (getint "Enter a number: ").[34] Both ensure controlled, non-expressive inputs that enhance script interactivity without disrupting AutoCAD's manual workflow.[34]
Drawing Database Access
AutoLISP provides several functions for accessing and modifying the entity data stored in AutoCAD's drawing database, which represents graphical objects such as lines, circles, and blocks. The primary function for retrieving this data is entget, which returns an association list (alist) containing the entity's definition data in the form of DXF (Drawing Interchange Format) group codes and their values. For instance, the expression (entget (car (entsel))) prompts the user to select an entity and retrieves its alist, where group code 10 represents the entity's primary point (e.g., (10 . (1.0 2.0 0.0))). This function supports optional extended data (Xdata) retrieval by specifying a list of registered application names.[35]
To modify entity properties, AutoLISP uses entmod in conjunction with list manipulation functions like subst. The entmod function updates an entity's data in the database by passing a modified alist, similar to the output of entget but with altered group code values; it requires the entity's name in the -1 group code to identify the target. For example, to change an entity's layer from its current value to "1", one retrieves the data with entget, replaces the layer association using (subst (cons 8 "1") (assoc 8 ed) ed), and applies the changes via entmod. The entsel function facilitates this by prompting the user for a single entity selection, returning a list containing the entity name and the pick point in the current UCS. Note that entmod cannot alter an entity's type, handle, or certain internal fields, and modifications to block definitions affect all instances.[36][37]
Database queries in AutoLISP target symbol tables, which store non-graphical data like layers, linetypes, and blocks. The tblsearch function searches a specified table (e.g., "LAYER" or "BLOCK") for a given symbol name and returns its alist if found, or nil otherwise; it can optionally set the next entry for tblnext iteration. Complementing this, tblnext iterates through table entries sequentially, returning the next alist or nil when exhausted, with an optional rewind argument to start from the beginning. For example, (tblnext "layer" T) retrieves the first layer entry as a dotted-pair list including codes like (2 . "0") for the layer name. These functions enable programmatic checks and enumerations of drawing resources.[38][39]
Access to nongraphical objects, such as dictionaries, is provided through the namedobjdict function, which returns the entity name of the drawing's root named object dictionary, serving as the entry point for all such structures. From there, dictionary-specific functions like dictsearch and dictnext allow querying and traversing entries, facilitating the management of custom data beyond symbol tables. For 3D and attribute handling, viewport manipulation involves commands like VPOINT, which sets the viewing direction via (command "vpoint" pt) where pt is a 3D point defining the vector from the target, and VIEW, which restores or saves named views; these integrate with entity traversal using entnext to chain through related entities, including attributes in blocks, by stepping to SEQEND markers. The entnext function retrieves the subsequent non-deleted entity after a given one (or the first if none specified), enabling full database scans and subentity navigation in complex objects like polylines or attributed blocks.[40][41][42]
Programming Techniques
Control Structures and Custom Functions
AutoLISP supports conditional branching through several built-in functions that evaluate test expressions and execute code accordingly. The if function provides a straightforward mechanism for binary decisions, taking a test expression and up to two additional expressions: one to evaluate if the test is non-nil (true) and an optional one if the test is nil (false). For instance, the expression (if (> x 0) "positive" "non-positive") evaluates to "positive" when x exceeds zero and "non-positive" otherwise.[43] The cond function extends this for multi-way branching, accepting pairs of test expressions and results, and returns the result from the first non-nil test or nil if none succeed.[44] Additionally, the while function combines conditional evaluation with repetition, executing a series of expressions repeatedly as long as its test expression remains non-nil, and returns the value of the last evaluated expression or nil if the loop never runs.[45]
Iteration in AutoLISP relies on looping constructs that handle counters, conditions, or list traversal without traditional for loops. The repeat function performs a fixed number of iterations, evaluating its expressions that many times and returning the last result; for example, (repeat 3 (setq count (+ count 1))) increments count three times.[46] The while function, as noted, enables condition-based loops, suitable for scenarios where the iteration count is unknown upfront. For list processing, foreach iterates over each element of a list, binding it to a symbol and evaluating expressions per element, then returns the last evaluated value; an example is (foreach item '(a b c) (princ item)), which prints each item sequentially.[47] These constructs facilitate efficient control flow for repetitive tasks in AutoLISP programs.
Custom functions in AutoLISP are defined using the defun function, which creates reusable code blocks with specified parameters and body expressions. The syntax is (defun function-name (arguments) body), where arguments lists required and optional parameters, and body contains the expressions to execute, with the last one providing the return value. Duplicate argument names are ignored after the first occurrence. For example:
(defun square (x)
(* x x)
)
(defun square (x)
(* x x)
)
This defines square to return the square of its numeric argument. To scope variables locally and avoid global pollution, a forward slash (/) delimiter follows the arguments, after which local variables are listed; these are initialized to nil at function entry and discarded upon exit. An example is:
(defun example (/ local-var)
(setq local-var 42)
local-var
)
(defun example (/ local-var)
(setq local-var 42)
local-var
)
Local variables must be separated from arguments and each other by spaces.[48][49][50]
Recursion is supported in AutoLISP, enabling functions to invoke themselves for tasks like tree or list traversal, though it requires careful management to prevent stack overflow in deep calls. Basic recursive processing of lists, such as summing elements via repeated cons deconstruction, is common and leverages the language's functional heritage. For instance, a simple recursive factorial function can be defined as (defun fact (n) (if (<= n 1) 1 (* n (fact (- n 1))))), computing n! by self-calling until the base case.[51]
Error Handling and Debugging
AutoLISP provides mechanisms for trapping and managing runtime errors, ensuring programs can respond gracefully to issues such as invalid inputs or user interruptions, thereby maintaining the integrity of the AutoCAD environment.[52] The primary global error handler is the *error* variable, which can be set to a user-defined function that executes when an error occurs, receiving a string describing the error as its argument.[53] This allows developers to restore system states, such as layer settings or undo markers, before the program halts. For instance, a custom error handler might check the error message and suppress output for user cancellations like "Function cancelled" or "quit / exit abort," while displaying others via princ.[53] It is essential to save the original *error* value before redefining it and restore it upon completion to avoid interfering with AutoCAD's default handling.[53]
Debugging in AutoLISP relies on output functions and tracing tools to inspect code execution. The princ function outputs expressions in a human-readable format without adding newlines or quotes, making it ideal for logging variable values during development, such as (princ (strcat "Current layer: " (getvar "CLAYER"))) to display the current layer without formatting artifacts.[54] Similarly, print adds a newline before and a space after the expression, facilitating clearer sequential output in the command line or a file for tracing program flow.[55] For step-by-step execution analysis, the trace function sets a flag on specified functions, displaying entry points, arguments, and return values with indentation based on call depth, either in the command line or the Visual LISP Trace window on Windows.[56] The untrace function clears these flags, and calling trace without arguments lists currently traced functions.[56] In the Visual LISP IDE (VLIDE), available on Windows, breakpoints can be set at specific code lines to pause execution, enabling inspection of variables and stepping through code with tools like Debug Step Into.[57] Breakpoints persist across sessions if settings are saved but require reloading the code after edits to maintain alignment.[57]
Common error types in AutoLISP include bad argument errors, such as providing too few arguments or invalid types to built-in functions like inters, which expects list pairs but fails on non-list inputs.[52] Quit interrupts occur when users press Esc or Ctrl+C during execution, triggering the error handler with messages like "quit / exit abort."[53] File I/O failures arise from issues like attempting to open nonexistent files with open, resulting in nil returns or error strings that must be checked.[52] The ERRNO system variable provides numeric error codes via (getvar "ERRNO") for more precise diagnosis.[53]
Best practices emphasize proactive error management to enhance robustness. The vl-catch-all-apply function, introduced in Visual LISP extensions, wraps risky expressions to catch exceptions without invoking *error*, returning the result or an error object that can be inspected with vl-catch-all-error-p and vl-catch-all-error-message.[58] For example, (if (vl-catch-all-error-p (setq result (vl-catch-all-apply 'some-function args))) (princ (vl-catch-all-error-message result)) result) allows conditional continuation.[58] To facilitate recovery, routines should establish undo marks using (command "._UNDO" "_MARK") at the start and invoke (command "._UNDO" "_BACK") in the error handler to revert changes, grouping multiple command calls into a single undo unit with "_Begin" and "_End" for cleaner rollback.[59] Custom error handlers should remain concise to minimize user interruption risks, as they can themselves be canceled.[53]
Practical Applications
Basic Programming Examples
AutoLISP, as a dialect of Lisp integrated with AutoCAD, enables users to automate basic drawing tasks through simple scripts and functions. These introductory examples illustrate core concepts such as variable assignment, arithmetic operations, entity selection, user input, and command invocation, drawing from fundamental AutoLISP syntax like setq for setting variables and command for interacting with AutoCAD commands.
A straightforward example involves calculating and labeling the area of a circle. The script prompts the user for the circle's radius, assigns it to a variable using setq, computes the area with the built-in *pi* constant and multiplication, and uses the command function to draw a text label at a specified point. This demonstrates arithmetic evaluation and output to the drawing.
lisp
(setq radius (getreal "\nEnter circle radius: "))
(setq area (* *pi* radius radius))
(command "TEXT" (getpoint "\nPick text location: ") 0.2 0 "Area: " (rtos area 2 2))
(setq radius (getreal "\nEnter circle radius: "))
(setq area (* *pi* radius radius))
(command "TEXT" (getpoint "\nPick text location: ") 0.2 0 "Area: " (rtos area 2 2))
This code first retrieves a real number input for the radius, calculates the area, and then executes the AutoCAD TEXT command to place the formatted area value, where rtos converts the numeric result to a string for display.
For handling selections, a routine can use ssget to create a selection set of entities and sslength to count them, providing a list of selected items for basic inventory. This example prompts the user to select objects in the drawing, determines the count, and prints the details to the command line using princ, showcasing list manipulation and selection fundamentals.
lisp
(setq ss (ssget))
(if ss
(progn
(setq count (sslength ss))
(princ (strcat "\nSelected " (itoa count) " entities."))
)
(princ "\nNo entities selected.")
)
(setq ss (ssget))
(if ss
(progn
(setq count (sslength ss))
(princ (strcat "\nSelected " (itoa count) " entities."))
)
(princ "\nNo entities selected.")
)
Here, ssget returns a selection set or nil if none are chosen; the if and progn ensure conditional execution, while itoa converts the integer count to a string for output. This approach is essential for scripts that process user-selected geometry without deeper entity analysis.
Custom functions in AutoLISP are defined with defun, allowing reusable code for tasks like drawing a line between two points. This basic function prompts for start and end points using getpoint, then invokes the LINE command to draw the segment, encapsulating input and drawing operations.
lisp
(defun c:drawline ()
(setq pt1 (getpoint "\nPick start point: "))
(if pt1
(setq pt2 (getpoint pt1 "\nPick end point: "))
)
(if (and pt1 pt2)
(command "LINE" pt1 pt2 "")
)
(princ)
)
(defun c:drawline ()
(setq pt1 (getpoint "\nPick start point: "))
(if pt1
(setq pt2 (getpoint pt1 "\nPick end point: "))
)
(if (and pt1 pt2)
(command "LINE" pt1 pt2 "")
)
(princ)
)
The c: prefix makes the function callable as an AutoCAD command. It uses conditional checks with if to validate points before proceeding, ensuring the line is only drawn if both inputs are provided, which highlights function definition and point-based input handling.
User interaction extends to customizing drawing environments, such as creating and setting a layer via string input. This program uses getstring to obtain a layer name, then employs the LAYER command to make it current if it exists or create it otherwise, illustrating string handling and command automation.
lisp
(setq layername (getstring "\nEnter layer name: "))
(command "LAYER" "M" layername "")
(princ (strcat "\nLayer '" layername "' set as current."))
(setq layername (getstring "\nEnter layer name: "))
(command "LAYER" "M" layername "")
(princ (strcat "\nLayer '" layername "' set as current."))
The getstring function captures textual input, and the LAYER command's "M" option sets the specified layer as current, with an empty string terminating the command sequence. This example is useful for preparing drawings with user-defined organization.
Advanced Customization Routines
Note: Some functions in these examples, such as those with vlax- prefix, require Visual LISP, available only in full AutoCAD for Windows.[1]
Advanced customization routines in AutoLISP leverage core programming features to develop intricate tools for AutoCAD, such as automated generation of parametric elements, data analysis and export, user-friendly interfaces, and efficient traversal of complex structures like nested blocks. These routines typically integrate loops for iteration, conditional logic for entity handling, and file operations for output, enabling scalable solutions that extend beyond basic scripting. By combining these elements, developers can create commands that respond to user inputs while interacting with the drawing database to produce precise, repeatable results.
One common advanced application is the creation of parametric drawings, where routines generate arrays of blocks based on user-specified parameters like spacing and quantity. For instance, a routine can prompt for horizontal and vertical spacing values along with the number of rows and columns, then use nested loops to insert block references at calculated positions. This is achieved using the entmake function to directly create INSERT entities without relying on AutoCAD commands, ensuring efficient execution in large drawings. The following representative code snippet illustrates this process, assuming a predefined block named "standard_block":
lisp
(defun c:creategrid (/ spacing rows cols row col x y)
(setq spacing (getreal "\nEnter spacing: "))
(setq rows (getint "\nEnter number of rows: "))
(setq cols (getint "\nEnter number of columns: "))
(setq row 0)
(while (< row rows)
(setq y (* row spacing))
(setq col 0)
(while (< col cols)
(setq x (* col spacing))
(entmake (list
'(0 . "INSERT")
(cons 2 "standard_block")
(cons 10 x y 0.0)
(cons 41 1.0) ; X scale
(cons 42 1.0) ; Y scale
(cons 43 1.0) ; Z scale
))
(setq col (1+ col))
)
(setq row (1+ row))
)
(princ "\nGrid created successfully.")
(princ)
)
(defun c:creategrid (/ spacing rows cols row col x y)
(setq spacing (getreal "\nEnter spacing: "))
(setq rows (getint "\nEnter number of rows: "))
(setq cols (getint "\nEnter number of columns: "))
(setq row 0)
(while (< row rows)
(setq y (* row spacing))
(setq col 0)
(while (< col cols)
(setq x (* col spacing))
(entmake (list
'(0 . "INSERT")
(cons 2 "standard_block")
(cons 10 x y 0.0)
(cons 41 1.0) ; X scale
(cons 42 1.0) ; Y scale
(cons 43 1.0) ; Z scale
))
(setq col (1+ col))
)
(setq row (1+ row))
)
(princ "\nGrid created successfully.")
(princ)
)
This approach draws on the entmake function's ability to construct entities from association lists, including required fields like entity type (0), block name (2), and insertion point (10). Such parametric generation is particularly useful for creating repetitive layouts like structural grids or equipment arrays, minimizing manual placement errors.
Data extraction scripts represent another sophisticated use case, allowing routines to query selected entities, compute aggregate properties such as total lengths, and export results to external files like CSV for further analysis. For curves including lines and polylines, the Visual LISP extension function vlax-curve-getDistAtParam computes the distance from the curve's start to a given parameter, enabling accurate length calculations by evaluating at the end parameter obtained via vlax-curve-getEndParam. A routine might select multiple linear entities, sum their lengths, and write the data—including individual lengths and totals—to a CSV file using file I/O functions like open and write-line. The illustrative code below demonstrates extracting lengths from selected objects and exporting to "lengths.csv":
lisp
(defun c:extractlengths (/ ss i obj len total file)
(if (setq ss (ssget '((0 . "LINE,LWPOLYLINE,POLYLINE,ARC,CIRCLE"))))
(progn
(setq total 0.0 i 0)
(setq file (open "lengths.csv" "w"))
(write-line "Entity,Length" file)
(while (< i (sslength ss))
(setq obj (vlax-ename->vla-object (ssname ss i)))
(if (vlax-property-available-p obj 'length)
(setq len (vla-get-length obj))
(setq len (vlax-curve-getDistAtParam obj (vlax-curve-getEndParam obj)))
)
(write-line (strcat "Entity" (itoa i) "," (rtos len 2 2)) file)
(setq total (+ total len))
(setq i (1+ i))
)
(write-line (strcat "Total," (rtos total 2 2)) file)
(close file)
(princ (strcat "\nTotal length: " (rtos total 2 2)))
)
)
(princ)
)
(defun c:extractlengths (/ ss i obj len total file)
(if (setq ss (ssget '((0 . "LINE,LWPOLYLINE,POLYLINE,ARC,CIRCLE"))))
(progn
(setq total 0.0 i 0)
(setq file (open "lengths.csv" "w"))
(write-line "Entity,Length" file)
(while (< i (sslength ss))
(setq obj (vlax-ename->vla-object (ssname ss i)))
(if (vlax-property-available-p obj 'length)
(setq len (vla-get-length obj))
(setq len (vlax-curve-getDistAtParam obj (vlax-curve-getEndParam obj)))
)
(write-line (strcat "Entity" (itoa i) "," (rtos len 2 2)) file)
(setq total (+ total len))
(setq i (1+ i))
)
(write-line (strcat "Total," (rtos total 2 2)) file)
(close file)
(princ (strcat "\nTotal length: " (rtos total 2 2)))
)
)
(princ)
)
This script utilizes vlax-curve-getDistAtParam to derive segment lengths for supported curve objects, providing a robust method for quantifying drawing elements like piping runs or boundary perimeters. The export functionality facilitates integration with external tools for reporting or costing.
Dialog integration enhances user interaction in advanced routines by incorporating Dialog Control Language (DCL) files to build custom forms, such as for batch editing block attributes. A basic DCL setup defines a dialog with labeled edit boxes corresponding to attribute tags, while the AutoLISP code loads the dialog, captures user inputs via action tiles, and applies changes to selected block references using functions like entnext and entmod. For attribute editing, the routine might prompt for a block selection, extract current values, populate the dialog fields, and update upon submission. The following DCL example ("attribedit.dcl") and corresponding AutoLISP ("attribedit.lsp") provide a foundational structure for a simple two-attribute editor:
DCL File (attribedit.dcl):
attribedit : dialog {
label = "Attribute Editor";
: edit_box {
key = "tag1";
label = "Attribute 1:";
edit_width = 20;
}
: edit_box {
key = "tag2";
label = "Attribute 2:";
edit_width = 20;
}
ok_cancel;
}
attribedit : dialog {
label = "Attribute Editor";
: edit_box {
key = "tag1";
label = "Attribute 1:";
edit_width = 20;
}
: edit_box {
key = "tag2";
label = "Attribute 2:";
edit_width = 20;
}
ok_cancel;
}
AutoLISP File (excerpt):
lisp
(defun c:editattribs (/ dcl_id insert-ent ent att1 att2 val1 val2)
(if (setq insert-ent (car (entsel "\nSelect block: ")))
(progn
(setq ent (entnext insert-ent))
(while ent
(if (= (cdr (assoc 0 (entget ent))) "ATTRIB")
(progn
(if (= (cdr (assoc 2 (entget ent))) "TAG1")
(setq att1 ent val1 (cdr (assoc 1 (entget ent))))
)
(if (= (cdr (assoc 2 (entget ent))) "TAG2")
(setq att2 ent val2 (cdr (assoc 1 (entget ent))))
)
)
)
(setq ent (entnext ent))
)
(if (and att1 att2)
(progn
(setq dcl_id (load_dialog "attribedit.dcl"))
(if (not (new_dialog "attribedit" dcl_id)) (exit))
(set_tile "tag1" val1)
(set_tile "tag2" val2)
(action_tile "accept" "(setq val1 (get_tile \"tag1\") val2 (get_tile \"tag2\")) (done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
(start_dialog)
(unload_dialog dcl_id)
(if (= (start_dialog) 1)
(progn
(entmod ([subst](/page/SUBST) (cons 1 val1) (assoc 1 (entget att1)) (entget att1)))
(entmod ([subst](/page/SUBST) (cons 1 val2) (assoc 1 (entget att2)) (entget att2)))
(entupd insert-ent)
)
)
)
)
)
)
(princ)
)
(defun c:editattribs (/ dcl_id insert-ent ent att1 att2 val1 val2)
(if (setq insert-ent (car (entsel "\nSelect block: ")))
(progn
(setq ent (entnext insert-ent))
(while ent
(if (= (cdr (assoc 0 (entget ent))) "ATTRIB")
(progn
(if (= (cdr (assoc 2 (entget ent))) "TAG1")
(setq att1 ent val1 (cdr (assoc 1 (entget ent))))
)
(if (= (cdr (assoc 2 (entget ent))) "TAG2")
(setq att2 ent val2 (cdr (assoc 1 (entget ent))))
)
)
)
(setq ent (entnext ent))
)
(if (and att1 att2)
(progn
(setq dcl_id (load_dialog "attribedit.dcl"))
(if (not (new_dialog "attribedit" dcl_id)) (exit))
(set_tile "tag1" val1)
(set_tile "tag2" val2)
(action_tile "accept" "(setq val1 (get_tile \"tag1\") val2 (get_tile \"tag2\")) (done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
(start_dialog)
(unload_dialog dcl_id)
(if (= (start_dialog) 1)
(progn
(entmod ([subst](/page/SUBST) (cons 1 val1) (assoc 1 (entget att1)) (entget att1)))
(entmod ([subst](/page/SUBST) (cons 1 val2) (assoc 1 (entget att2)) (entget att2)))
(entupd insert-ent)
)
)
)
)
)
)
(princ)
)
This integration of DCL with AutoLISP allows for intuitive attribute modifications, streamlining workflows for title blocks or labeled components by avoiding repetitive command-line edits. The code assumes a block with exactly two attributes tagged "TAG1" and "TAG2"; for general use, tag matching can be parameterized.
For optimization in handling complex drawings, recursive functions enable efficient traversal of nested block hierarchies to identify and modify attribute definitions without redundant processing. Such a routine accesses block definitions via tblobjname and iterates through their entities using entnext, recursing on any nested INSERT entities while applying changes only to ATTDEF elements matching specified criteria. This prevents duplication in deeply nested structures by maintaining a visited set or depth limit. A representative recursive function might traverse from a root block name, modifying the default value of a target attribute definition in the block definition and its nested sub-blocks:
lisp
(defun modify-nested-attribs (rootblk tag newval / blkobj ent edata subblk visited)
(setq visited '())
(defun recurse (blkname / ent edata)
(if (not (member blkname visited))
(progn
(setq visited (cons blkname visited))
(setq blkobj (tblobjname "BLOCK" blkname))
(if blkobj
(progn
(setq ent (entnext blkobj))
(while ent
(setq edata (entget ent))
(cond
((= (cdr (assoc 0 edata)) "INSERT")
(setq subblk (cdr (assoc 2 edata)))
(recurse subblk)
)
((= (cdr (assoc 0 edata)) "ATTDEF")
(if (= (cdr (assoc 2 edata)) tag)
(entmod (subst (cons 1 newval) (assoc 1 edata) edata))
)
)
)
(setq ent (entnext ent))
)
)
)
)
)
)
(recurse rootblk)
(command "_.REGEN")
(princ)
)
(defun modify-nested-attribs (rootblk tag newval / blkobj ent edata subblk visited)
(setq visited '())
(defun recurse (blkname / ent edata)
(if (not (member blkname visited))
(progn
(setq visited (cons blkname visited))
(setq blkobj (tblobjname "BLOCK" blkname))
(if blkobj
(progn
(setq ent (entnext blkobj))
(while ent
(setq edata (entget ent))
(cond
((= (cdr (assoc 0 edata)) "INSERT")
(setq subblk (cdr (assoc 2 edata)))
(recurse subblk)
)
((= (cdr (assoc 0 edata)) "ATTDEF")
(if (= (cdr (assoc 2 edata)) tag)
(entmod (subst (cons 1 newval) (assoc 1 edata) edata))
)
)
)
(setq ent (entnext ent))
)
)
)
)
)
)
(recurse rootblk)
(command "_.REGEN")
(princ)
)
This method scans block definitions for nested inserts, as recommended for working with blocks in AutoLISP, ensuring modifications to attribute defaults propagate through hierarchies like assembly drawings. To update existing instances, additional traversal of INSERT entities and their ATTRIB is required, or use the ATTSYNC command.
Extensions and Modern Developments
Visual LISP Enhancements
Visual LISP (VLISP) was introduced with AutoCAD 2000 as an extension to AutoLISP, providing an ActiveX-compatible layer that enhances the language with support for COM automation and variant data types through dedicated vl- functions.[60] This integration allows developers to interact with AutoCAD's object model more robustly, bridging traditional LISP scripting with Windows-based automation technologies.[61] Prior to full integration, a precursor known as Vital LISP served as an add-on for AutoCAD Release 14, but Visual LISP marked a significant evolution by embedding these capabilities directly into the core platform.[62]
Key enhancements in Visual LISP include the VLA-object model, which enables object-oriented access to drawing entities and properties via ActiveX interfaces, such as retrieving an entity's color with (vlax-get-property obj 'Color).[63] This model supports functions like vlax-ename->vla-object to convert entity names to VLA-objects, facilitating more intuitive manipulation of AutoCAD elements compared to traditional ename-based access.[64] Additionally, reactors introduce event-driven programming, allowing applications to respond to drawing events through types like command reactors (:VLR-Command-Reactor) and object reactors (:VLR-Object-Reactor), which notify code of actions such as entity modifications or command executions.[65]
The Visual LISP Integrated Development Environment (VLIDE), invoked via the VLIDE command, offers advanced tools for development, including an integrated text editor with syntax highlighting and color-coding for AutoLISP and DCL code, watch windows for monitoring variables and expressions, and project management for handling multi-file applications.[66] Debugging capabilities within VLIDE, such as stepping through code and inspecting objects with tools like vlax-dump-object, streamline the testing process directly within AutoCAD.[66]
Visual LISP maintains full backward compatibility with pure AutoLISP code, ensuring existing scripts run without modification while adding enhancements like automatic garbage collection for memory management—invoked via vlax-release-object to free VLA-object resources—and structured error handling through functions such as vl-catch-all-apply, which returns error objects for trapping exceptions without halting execution.[67] These features, including vl-catch-all-error-p to check for errors and vl-catch-all-error-message to retrieve details, improve program robustness in complex automation tasks.[68]
In recent years, Autodesk has shifted focus toward modern, cross-platform development environments for AutoLISP, with the AutoCAD AutoLISP Extension for Visual Studio Code serving as a primary tool. Released in 2021 alongside AutoCAD 2021, this extension integrates AutoLISP support directly into the free, open-source Visual Studio Code editor, enabling developers to edit, compile, and debug LSP files without relying on legacy integrated development environments.[69] It provides key features such as syntax highlighting, code snippets for common AutoLISP constructs, IntelliSense for autocompletion of functions and variables, and integrated debugging that connects to running AutoCAD sessions for step-through execution and breakpoint management.[70] Enhancements introduced in AutoCAD 2023 further improved the extension by adding project management capabilities, support for advanced debug configurations at the extension level, and streamlined loading of LSP files into AutoCAD, making it suitable for both individual scripts and larger codebases.[71] As a cross-platform solution compatible with Windows, macOS, and Linux, it addresses limitations of older tools by offering a lightweight yet powerful editor that fosters collaboration and version control integration via extensions like Git.[72]
Beyond Autodesk's ecosystem, alternative CAD platforms like BricsCAD provide robust LISP support with extensions that enhance AutoLISP compatibility. BricsCAD's LISP engine includes a suite of extended functions—such as those prefixed with "vle-" for advanced entity manipulation and system interactions—that go beyond standard AutoLISP, allowing developers to access BricsCAD-specific features like parametric block editing and machine learning integrations without rewriting code.[73] These extensions are documented in BricsCAD's developer reference and supported through its built-in LISP editor, which offers debugging and loading similar to AutoCAD's tools, making it a viable option for users migrating from or supplementing AutoCAD workflows.[74] For third-party editors serving as alternatives to the retired Visual LISP IDE (VLIDE), developers often turn to general-purpose tools like Notepad++ for lightweight syntax-highlighted editing of LSP files, though these lack native debugging and require manual loading into AutoCAD.[75] Online sandboxes specifically for AutoLISP remain limited, with general LISP compilers like those for Common Lisp available for basic testing, but full AutoLISP execution still necessitates a CAD host environment.[76]
As of AutoCAD 2025, AutoLISP enjoys full integration across desktop and cloud environments, marking a significant expansion with native support added to AutoCAD LT for the first time, enabling automation in this lighter version while maintaining compatibility with core functions like entity access and command invocation—albeit without third-party libraries or the Visual LISP IDE.[77] This release emphasizes modern tools like the VS Code extension over legacy interfaces, with VLIDE still accessible via the VLISP command but no longer the default or recommended editor, reflecting a de-emphasis on older modes such as DOS-era LISP compatibility that have been obsolete since the transition to Windows-based AutoCAD.[78] For cloud-based scripting, AutoLISP is accessible through Autodesk Platform Services (APS), allowing developers to run scripts on web-hosted AutoCAD instances for automated processing of drawings without local installation, supporting workflows like batch design modifications and API-driven customizations.[79] These advancements build on Visual LISP enhancements from earlier eras by prioritizing extensible, platform-agnostic tools that align with contemporary software development practices.[3]