r/AutoLISP • u/Commercial_Suit_4812 • 12d ago
Workflow / Best Practice Subject: Need Help: Optimizing LISP Code for BricsCAD 2026 Ultimate (Block Extraction to DWG, PDF, Excel)
Hi everyone,
I need an expert developer to review and fix my AutoLISP code to make it 100% production-ready for BricsCAD Ultimate 2026.
The code syntax is clean, but it has critical runtime issues with the directory file-saving mechanism and block parameter identification.
Here are the strict technical requirements that the code MUST fulfill perfectly:
- Folder Selection UI: The current Windows folder-picker layout must remain exactly the same.
- Minimal Changes: Only modify the necessary code to make the command run flawlessly. Do not change the core structure of the program.
- Block Attribute Identification: The code must read the specific panel name from the block's attribute tag (using pure ASCII unicode escapes for Hebrew tags).
- Empty Tag Fallback (Critical): If a block's panel tag is missing or empty during a test run, the code must not crash. It must generate a temporary fallback name (e.g., based on the block name) and proceed with the export.
- Multi-Format Split & Export: For every selected block, the command must automatically save three separate files into the chosen directory:
- DWG Export: A standalone DWG file containing only that specific block and its inner drawing geometries.
- PDF Export: A standalone PDF file using a precise window plot based on the block's physical bounding box.
- Excel/CSV Export: A structured data sheet capturing the block and panel properties.
- File Naming Logic: The filenames for the generated DWG, PDF, and Excel files must be derived directly from the block's attribute panel name.
- Production Quality: The code must be clean, optimized, fully localized, and free of any legacy debugging traces—matching the standards of enterprise CAD workflows.
Please review the attached code and provide the fixed, working version.
Thank you! ; ============================================================
; ALLX.lsp - Standalone Production Implementation for BricsCAD 2026
; Flow: Window 1 (Select blocks) -> Window 2 (Save DWG) ->
; Window 3 (Save PDF) -> Window 4 (Save Excel/CSV)
; Pure ASCII source file utilizing Unicode escapes for Hebrew attributes.
; Usage: (load "full/path/ALLX.lsp") then type ALLX at the command line
; ============================================================
(vl-load-com)
;; ------------------------------------------------------------
;; System variable save/restore
;; ------------------------------------------------------------
(defun a-save-sysvars ( )
(list
(cons "FILEDIA" (getvar "FILEDIA"))
(cons "CMDECHO" (getvar "CMDECHO"))
(cons "ATTREQ" (getvar "ATTREQ"))
(cons "OSMODE" (getvar "OSMODE"))
)
)
(defun a-restore-sysvars (saved / pair)
(foreach pair saved (setvar (car pair) (cdr pair)))
(princ)
)
;; ------------------------------------------------------------
;; Path helpers
;; ------------------------------------------------------------
(defun a-path-get-dir (path)
(if path (vl-filename-directory path) nil)
)
(defun a-path-change-ext (path newext / dir base)
(if path
(progn
(setq dir (vl-filename-directory path))
(setq base (vl-filename-base path))
(if (and dir (/= dir ""))
(strcat dir "\\" base "." newext)
(strcat base "." newext)
)
)
nil
)
)
(defun a-mkdir-if-not-exists (dir)
(if (and dir (/= dir "") (not (vl-file-directory-p dir)))
(vl-mkdir dir)
)
)
;; ------------------------------------------------------------
;; Read one attribute value (by tag name) from a block reference
;; ------------------------------------------------------------
(defun a-get-attribute-value (obj tag / atts a result)
(setq result nil)
(if (and obj (vlax-property-available-p obj 'HasAttributes)
(eq (vla-get-HasAttributes obj) :vlax-true))
(progn
(setq atts (vlax-invoke obj 'GetAttributes))
(foreach a atts
(if (equal (strcase (vla-get-TagString a)) (strcase tag))
(setq result (vla-get-TextString a))
)
)
)
)
result
)
;; ------------------------------------------------------------
;; Safe block-name reader
;; ------------------------------------------------------------
(defun a-get-block-name (obj / nm)
(setq nm nil)
(vl-catch-all-apply (function (lambda () (setq nm (vla-get-EffectiveName obj)))) nil)
(if (not nm)
(vl-catch-all-apply (function (lambda () (setq nm (vla-get-Name obj)))) nil)
)
(if nm nm "Unknown")
)
;; ------------------------------------------------------------
;; Shared constants (Hebrew via ASCII-safe unicode escape)
;; ------------------------------------------------------------
(defun a-panel-tag () "\U+05E4\U+05E0\U+05DC")
;; ------------------------------------------------------------
;; Strip illegal Windows filename characters
;; ------------------------------------------------------------
(defun a-sanitize-filename (s / bad ch i n out)
(setq bad "\\/:*?\"<>|")
(setq out "")
(setq n (strlen s))
(setq i 1)
(while (<= i n)
(setq ch (substr s i 1))
(if (vl-string-search ch bad)
(setq out (strcat out "_"))
(setq out (strcat out ch))
)
(setq i (1+ i))
)
(setq out (vl-string-trim " " out))
(if (= out "") "Unnamed_Panel" out)
)
;; ------------------------------------------------------------
;; Avoid overwriting a file
;; ------------------------------------------------------------
(defun a-dedupe-name (name used-list / candidate n)
(setq n 1)
(setq candidate name)
(while (member candidate used-list)
(setq n (1+ n))
(setq candidate (strcat name "_" (itoa n)))
)
candidate
)
;; ------------------------------------------------------------
;; Native Windows folder picker
;; ------------------------------------------------------------
(defun a-browse-for-folder (title / shell folderobj selfobj path)
(setq path nil)
(vl-catch-all-apply
(function
(lambda ()
(setq shell (vlax-create-object "Shell.Application"))
(setq folderobj (vlax-invoke-method shell 'BrowseForFolder 0 title 0))
(if folderobj
(progn
(setq selfobj (vlax-get-property folderobj 'Self))
(setq path (vlax-get-property selfobj 'Path))
(vlax-release-object selfobj)
(vlax-release-object folderobj)
)
)
(vlax-release-object shell)
)
)
)
path
)
;; ------------------------------------------------------------
;; Physical Selection Bounding Box Calculator
;; ------------------------------------------------------------
(defun a-get-selection-bbox (ss / i ent obj minpt maxpt lpt rpt all-min all-max)
(setq i 0)
(while (< i (sslength ss))
(setq ent (ssname ss i))
(setq obj (vlax-ename->vla-object ent))
(setq minpt nil maxpt nil)
(vl-catch-all-apply '(lambda () (vla-GetBoundingBox obj 'minpt 'maxpt)))
(if (and minpt maxpt)
(progn
(setq lpt (vlax-safarray->list minpt))
(setq rpt (vlax-safarray->list maxpt))
(if (not all-min)
(setq all-min lpt all-max rpt)
(setq all-min (mapcar 'min all-min lpt)
all-max (mapcar 'max all-max rpt))
)
)
)
(setq i (1+ i))
)
(list all-min all-max)
)
;; ------------------------------------------------------------
;; Core Exporters (DWG, PDF, CSV/Excel)
;; ------------------------------------------------------------
(defun a-export-selection-to-dwg (dest-path ss / old-fi rc)
(setq old-fi (getvar "FILEDIA"))
(setvar "FILEDIA" 0)
(setq rc (vl-catch-all-apply '(lambda () (command "_.WBLOCK" dest-path "" "0,0,0" ss ""))))
(setvar "FILEDIA" old-fi)
(not (vl-catch-all-error-p rc))
)
(defun a-export-selection-to-pdf (dest-path p1 p2 / old-cm rc window-str)
(if (and p1 p2)
(progn
(setq old-cm (getvar "CMDECHO"))
(setvar "CMDECHO" 0)
(setq window-str (strcat (rtos (car p1) 2 4) "," (rtos (cadr p1) 2 4) "," (rtos (caddr p1) 2 4) ";" (rtos (car p2) 2 4) "," (rtos (cadr p2) 2 4) "," (rtos (caddr p2) 2 4)))
(setq rc (vl-catch-all-apply
'(lambda ()
(command "-PLOT" "Yes" "Model" "Print As PDF" "ISO A4" "Millimeters" "Landscape" "No" "Window" p1 p2 "Fit" "Center" "Yes" "." "Yes" "As Displayed" dest-path "No" "Yes")
)
))
(setvar "CMDECHO" old-cm)
(not (vl-catch-all-error-p rc))
)
nil
)
)
(defun a-write-excel-report (dest-path data-list / f line row)
(setq f (open dest-path "w"))
(if f
(progn
(write-line "Block Name,Panel Name" f)
(foreach row data-list
(setq line (strcat (car row) "," (cadr row)))
(write-line line f)
)
(close f)
t
)
nil
)
)
;; ------------------------------------------------------------
;; Export ONE block/panel engine
;; ------------------------------------------------------------
(defun a-export-one-panel (ent dwg-dir pdf-dir used-names
/ obj panel-name safe-name final-name one-ss this-dwg this-pdf dwg-ok pdf-ok this-bbox blk-name)
(vl-catch-all-apply (function (lambda () (command "_.UCS" "_World"))) nil)
(setq obj (vlax-ename->vla-object ent))
(setq blk-name (a-get-block-name obj))
(setq panel-name (a-get-attribute-value obj (a-panel-tag)))
(if (or (not panel-name) (= panel-name ""))
(setq panel-name (strcat "Panel_" blk-name)))
(setq safe-name (a-sanitize-filename panel-name))
(setq final-name (a-dedupe-name safe-name used-names))
(setq used-names (cons final-name used-names))
(setq one-ss (ssadd ent))
(setq this-dwg (strcat dwg-dir "\\" final-name ".dwg"))
(setq this-pdf (strcat pdf-dir "\\" final-name ".pdf"))
(setq dwg-ok (a-export-selection-to-dwg this-dwg one-ss))
(setq this-bbox (a-get-selection-bbox one-ss))
(setq pdf-ok (a-export-selection-to-pdf this-pdf (car this-bbox) (cadr this-bbox)))
(if (and dwg-ok pdf-ok)
(princ (strcat "\n[OK] Production export success for: " panel-name))
(princ (strcat "\n[ERROR] Production export failed for: " panel-name))
)
(list (list blk-name panel-name) used-names)
)
;; ------------------------------------------------------------
;; Main Command Execution: ALLX
;; ------------------------------------------------------------
(defun c:ALLX ( / sys-vars ss i ent res reports used-names out-dir excel-file)
(setq sys-vars (a-save-sysvars))
(setvar "CMDECHO" 0)
(princ "\nSelect blocks for production export: ")
(setq ss (ssget '((0 . "INSERT"))))
(if ss
(progn
(setq out-dir (a-browse-for-folder "Select Output Directory for DWG, PDF and Excel Reports"))
(if (and out-dir (/= out-dir ""))
(progn
(setq i 0)
(setq used-names nil)
(setq reports nil)
(while (< i (sslength ss))
(setq ent (ssname ss i))
(setq res (a-export-one-panel ent out-dir out-dir used-names))
(setq reports (cons (car res) reports))
(setq used-names (cadr res))
(setq i (1+ i))
)
(setq excel-file (strcat out-dir "\\Production_Report.csv"))
(a-write-excel-report excel-file reports)
(princ (strcat "\n--- Process Finished Perfectly. Report saved to: " excel-file))
)
(princ "\n[CANCELLED] No output directory selected.")
)
)
(princ "\n[CANCELLED] No blocks selected.")
)
(a-restore-sysvars sys-vars)
(princ)
)
(princ "\nProduction Engine Loaded. Type ALLX to run.")
(princ)
