Autocad Error "error: bad arguement type: lselsetp nil" when selecting polyline - lisp

I am currently attempting to run a polyline between two blocks (first_block, second_block) that runs along another polyline, at the end of the action an insert function is called that populates an annotation block (cable_name_tag) with the details of the start and end block.
This polyline will transect other blocks and often needs to run in paralell with an underlying polyline (cable_ducting) so the user will need to option to select an appropriate part of the polyline to drop the annotation, as space is sometimes limited.
I have noted that if I comment out the second_block and provide a harcoded value the ssget function works without issue, so I am reasonably sure the issue is with either the syntax or the handling of the first_block and second_block in that code.
(defun c:cable ()
(vl-load-com)
(setvar "clayer" "cable layer")
(setvar "celtype" "bylayer")
(setvar "osmode" 515)
(command "_.pline"
(getpoint))
(while (> (getvar ' cmdactive) 0)
(command pause)
(princ "\npress enter to finish:"))
(setq elst
(entsel "\nselect cable segment: "))
(setq ename
(car elst))
(setq pt
(cadr elst))
(setq annopt pt)
(setq pt
(vlax-curve-getclosestpointto ename pt))
(setq param
(vlax-curve-getparamatpoint ename pt))
(setq preparam
(fix param))
(setq postparam
(1+ preparam))
(list (setq pt1
(vlax-curve-getpointatparam ename preparam))
(setq pt2
(vlax-curve-getpointatparam ename postparam)))
(setq cable
(entlast))
(setq cable_start
(vlax-curve-getstartparam cable))
(setq cable_start_point
(vlax-curve-getstartpoint cable))
(setq cable_end_point
(vlax-curve-getendpoint cable))
(setq cable_end
(angtos (angle '(0 0)
(vlax-curve-getfirstderiv cable 0.0))))
(setq first_block
(ssget "_c" cable_start_point cable_end_point
(list (cons 0 "insert")
(cons 2 "first_block"))))
(setq second_block
(ssget "_c" cable_start_point cable_end_point
(list (cons 0 "insert")
(cons 2 "second_block"))))
(setq end_cable
(ssname second_block 0))
(setq start_cable
(ssname first_block 0))
(setq $end_cable
(vla-get-textstring
(cadr (vlax-safearray->list
(variant-value
(vla-getattributes
(vlax-ename->vla-object end_cable)))))))
(setq $start_cable
(vla-get-textstring
(cadr (vlax-safearray->list
(variant-value
(vla-getattributes
(vlax-ename->vla-object start_cable)))))))
(setq cable_name
(vlax-curve-getendparam cable))
(command ; insert cable param
"-insert"
"cable_name_tag"
annopt
"1"
"1"
cable_angle
cable_name
$start_cable
$end_cable
"144"
cable_length))
I am stuck in a corner on this one, and would appreciate any help, advice or pointers anyone can offer.
Thank you all for your time.

Why not just use (entlast) to get the entity that was just created?

Related

AutoCAD LISP automatizing polyline drawings

I would like to ask a question about automatizing polyline drawing. Here I have a FUNC and I want to add more specific commands. What I mean: I want the polyline to be assigned to a chosen layer automatically and i also want to set the line type to my custom line type. Thanks for the answers.
Here is my code:
You can get the newly created polyline with the entlast function and change its properties with _chprop command.
(defun c:nyomvodal (/ pt lst)
;; create a new layer
(command "_layer" "_new" "nyomvodal" "_color" 3 "nyomvodal" "")
;; get points form user
(while (setq pt (getpoint "\nPick point: "))
(setq lst (cons pt lst))
)
(if (< 2 (length lst))
(progn
;; create the polyline
(command "_pline")
(foreach p (reverse lst)
(command "_non" p)
)
(command "")
(command "_chprop" (entlast) "" "_layer" "nyomvodal" "_ltype" "axes" "")
)
)
(princ)
)
But, typically, we save current values of the OSMODE, CLAYER and CELTYPE system variables, set new values, draw the polyline, and restore the previous values.
(defun c:nyomvodal (/ osmode clayer celtype)
;; save the current osmode, clayer and celtype
(setq osmode (getvar "osmode"))
(setq clayer (getvar "clayer"))
(setq celtype (getvar "celtype"))
;; create a new layer and make it current
(command "_layer" "_make" "nyomvodal" "_color" 3 "nyomvodal" "")
;; set the current osmode and line type
(setvar "osmode" 0)
(setvar "celtype" "AXES")
;; use vla-catch-all-apply to avoid exiting code if user cancels
(vl-catch-all-apply
'(lambda (/ pt lst)
;; get points form user
(while (setq pt (getpoint "\nPick point: "))
(setq lst (cons pt lst))
)
(if (< 2 (length lst))
(progn
;; create the polyline
(command "_pline")
(foreach p (reverse lst)
(command p)
)
(command "")
)
)
)
)
;; restore the previous system variables values
(setvar "osmode" osmode)
(setvar "clayer" clayer)
(setvar "celtype" celtype)
(princ)
)

How do you write an emacs lisp function to replace a word at point?

I have tried in two different ways to write my function. I decided to write a small function to convert to camel case and back with this elisp string library. At first via searching I found this tutorial on replacing things at point and made this function:
; use string manipulation library to switch between camel and snake (s.el)
(defun my_test ()
"test"
(interactive)
;; get current selection or word
(let (bds p1 p2 inputStr resultStr)
;; get boundary
(if (use-region-p)
(setq bds (cons (region-beginning) (region-end) ))
(setq bds (bounds-of-thing-at-point 'word)) )
(setq p1 (car bds) )
(setq p2 (cdr bds) )
;; grab the string
(setq inputStr (buffer-substring-no-properties p1 p2) )
(setq resultStr (s-lower-camel-case inputStr))
(message inputStr)
(delete-region p1 p2 ) ; delete the region
(insert resultStr) ; insert new string
)
)
This does not modify resultStr as expected and just repasts inputStr in there.
What I don't understand about this is that when I eval (with M-:) (setq resultStr (s-lower-camel-case "other_string")) I get the expected result ("otherString")
I even tried a different (and better for my purposes) way of writing the function inspired by this SO question:
(defun change-word-at-point (fun)
(cl-destructuring-bind (beg . end)
(bounds-of-thing-at-point 'word)
(let ((str (buffer-substring-no-properties beg end)))
(delete-region beg end)
(insert (funcall fun str)))))
(defun my_test_camel ()
(interactive)
(change-word-at-point 's-lower-camel-case))
which suffers from the same problem. This makes me think that there is something wrong with the s-lower-camel-case function (or how I am calling it) but that works when called from eval as mentioned above
EDIT: modified first function to include let syntax, see comments
EDIT #2: Both of these functions work correctly, the answer has been accepted as it provides a better alternative with the information on symbol and the correct way of writing it. My problem was testing which was due to haskell-mode. New question is here
Here's an alternate definition. The comment was correct that you need to do local bindings via let. Note that this version uses the region if it's active, or else uses bounds-of-thing-at-point to get the word at point if no region is active:
(defun word-or-region-to-lcc ()
"Convert word at point (or selected region) to lower camel case."
(interactive)
(let* ((bounds (if (use-region-p)
(cons (region-beginning) (region-end))
(bounds-of-thing-at-point 'symbol)))
(text (buffer-substring-no-properties (car bounds) (cdr bounds))))
(when bounds
(delete-region (car bounds) (cdr bounds))
(insert (s-lower-camel-case text)))))
If you didn't care about the option to use region, you could bind text locally to (thing-at-point 'symbol) instead of the call to buffer-substring-no-properties.
UPDATE. It turns out you can use (thing-at-point 'symbol) rather than (thing-at-point 'word) to get the full symbol for snake case.

Emacs -- remove an overlay `after-string` with a variable value

What is the proper way, please, to remove after-string overlays with variable values?
When using C-u C-x =, it only shows up as after-string without stating what the value is.
For example, once I lay an overlay using (overlay-put (make-overlay (point) (point)) 'after-string my-concatenated-string), I would like to be able to delete it without programming Emacs to remember every single my-concatenated-string that was previously used in the buffer -- there might be a few different ones on every line?
Is it sufficient to use?: (remove-overlays (window-start) (window-end)) 'after-string)
Or, is it better to use?: (remove-overlays (window-start) (window-end)) 'after-string t)
Or, is there another method to get them all?
EDIT (March 17, 2014):  My confusion is apparently coming from a misunderstanding between an object and a property.
In general, an overlay property is created as follows:
(overlay-put (make-overlay (point) (point)) 'my-property 'property-number-one )
In general, an overlay object is created as follows:
(overlay-put (make-overlay (point) (+ (point) 1))
'face '(:background "gray50" :foreground "black"))
Here is a unique situation where an 'after-string smells-like an object. My assumption is: if it smells-like an object, then perhaps a value needs to be included when attempting to remove it so that I'm not left with a disconnected 'after-string:
(save-excursion
(end-of-line)
(let ((eol-floating-column (+ (current-column) 10)))
(overlay-put (make-overlay (point) (point))
'after-string
(concat
(propertize (char-to-string ?\uE001)
'display
`((space :align-to ,eol-floating-column)
(space :width 0)))
(propertize (char-to-string ?\u00B6)
'face '(:background "gray50" :foreground "black")
'cursor t) ))))
The way the code is written, if you omit the last parameter, it only removes an overlay if the value is `nil' (which it doesn't appear to be in your case).
As you don't know the value of the property, I don't think you can use the function. However, you can simply write something like (assuming the value of the after-string is never nil):
(dolist (o (overlays-in (window-start) (window-end)))
(when (overlay-get o 'after-string)
(delete-overlay o))
Also note that if you do this from a post-command hook, window-end might not reflect the true value. To be safe you can do (window-end nil t), however this could be a bit slower.
When you put the overlay, add another property (like (overlay-put ol 'lawlist t), for example), after which you can remove those overlays with (remove-overlays BEG END 'lawlist t).
(defun lawlist-remove-overlays (beg end name val)
"Remove the overlays."
;; DEBUGGING
;; (unless (and beg end name val)
;; (message "ERROR -- beg: %s | end: %s | name: %s | val: %s" beg end name val))
(let* (
(point-max (point-max))
(point-min (point-min))
(narrowed-p (not (equal (- point-max point-min) (buffer-size))))
(beg (if beg beg point-min))
(end
(cond
((and
(not narrowed-p)
end)
end)
((and
(not narrowed-p)
(null end))
point-max)
((and
narrowed-p
end
(< end point-max))
end)
((and
narrowed-p
end
(= end point-max))
(1+ end))
((and
narrowed-p
(null end))
(1+ point-max)) )))
(when (and beg end name val)
(overlay-recenter end)
(dolist (o (overlays-in beg end))
(when (eq (overlay-get o name) val)
(delete-overlay o))))))
(dolist (description `(
,fci-pre-limit-string
,fci-pre-limit-active-region-string
,fci-at-limit-string
,fci-post-limit-string
,fci-wrapped-limit-string
,fci-cursor-at-eol-string
,fci-tab-text-left
,fci-tab-text-right
,fci-tab-sandwiched))
(lawlist-remove-overlays nil nil 'after-string description))
See also this related thread which deals with targeting overlays with values containing text properties:
https://emacs.stackexchange.com/a/9847/2287

Toggle case of next letter in elisp

I'd like to be able to toggle the case of the letter under the point. To that end, I wrote this:
(defun toggle-case-next-letter ()
"Toggles the case of the next letter, then moves the point forward one character"
(interactive)
(let* ((p (point))
(upcased (upcasep (char-after)))
(f (if upcased 'downcase-region 'upcase-region)))
(progn
(f p (+ 1 p))
(forward-char))))
However, when I run it (I've bound it to M-#), I get progn: Symbol's function definition is void: f. I assume this means f isn't bound, but I'm not sure.
Upcasep is defined as:
(defun upcasep (c) (eq c (upcase c)))
Is the problem in the let binding, or something else? (Also, if there's a better way to do this, that'd be nice as well).
Note that originally I had (upcased (upcasep (buffer-substring-no-properties p (+ 1 p)))), which I've corrected to (upcased (upcasep (char-after)), because using upcasep as defined above is always nil for strings (so I couldn't downcase again).
You've got a typical case of lisp-1 / lisp-2 confusion. Here's a fix (just a funcall):
(defun toggle-case-next-letter ()
"Toggles the case of the next letter, then moves the point forward one character"
(interactive)
(let* ((p (point))
(upcased (char-upcasep (buffer-substring-no-properties p (+ 1 p))))
(f (if upcased 'downcase-region 'upcase-region)))
(progn
(funcall f p (+ 1 p))
(forward-char))))
And here's what I have:
(global-set-key (kbd "C->") 'upcase-word-toggle)
(global-set-key (kbd "C-z") 'capitalize-word-toggle)
(defun char-upcasep (letter)
(eq letter (upcase letter)))
(defun capitalize-word-toggle ()
(interactive)
(let ((start (car
(save-excursion
(backward-word)
(bounds-of-thing-at-point 'symbol)))))
(if start
(save-excursion
(goto-char start)
(funcall
(if (char-upcasep (char-after))
'downcase-region
'upcase-region)
start (1+ start)))
(capitalize-word -1))))
(defun upcase-word-toggle ()
(interactive)
(let ((bounds (bounds-of-thing-at-point 'symbol))
beg end
regionp)
(if (eq this-command last-command)
(setq regionp (get this-command 'regionp))
(put this-command 'regionp nil))
(cond
((or (region-active-p) regionp)
(setq beg (region-beginning)
end (region-end))
(put this-command 'regionp t))
(bounds
(setq beg (car bounds)
end (cdr bounds)))
(t
(setq beg (point)
end (1+ beg))))
(save-excursion
(goto-char (1- beg))
(and (re-search-forward "[A-Za-z]" end t)
(funcall (if (char-upcasep (char-before))
'downcase-region
'upcase-region)
beg end)))))
I couldn't get #abo-abo's answer working for me but using his comments I was able to google better and found the following at http://chneukirchen.org/dotfiles/.emacs
(defun chris2-toggle-case ()
(interactive)
(let ((char (following-char)))
(if (eq char (upcase char))
(insert-char (downcase char) 1 t)
(insert-char (upcase char) 1 t)))
(delete-char 1 nil)
(backward-char))
(global-set-key (kbd "M-#") 'chris2-toggle-case)
This answers the original question if you remove (backward-char).
I realize this is a very old question, but having stumbled upon the same problem recently, I'd like to suggest a simpler solution.
I start with a pure function for toggling character case, based on char code property inspection:
(cl-defun toggle-char-case (c)
(cl-case (get-char-code-property c 'general-category)
(Lu (downcase c))
(Ll (upcase c))
(t c)))
I then use it from within an interactive function operating at point:
(cl-defun toggle-char-case-at-point ()
(interactive)
(let ((new (toggle-char-case (char-after))))
(delete-char 1)
(insert new)))
I then bound this interactive function to a keybinding of my choice:
(global-set-key (kbd "C-M-c") 'toggle-char-case-at-point)
The way this function operates is, after toggling the case it advances the point by one. So calling it repeatedly will toggle the cases of a sequence of chars. One could make it keep the point unchanged - that would require adding (backward-char) to the body.

Emacs: how to write a defun which acts on region, but acts on point if there's no region?

I write a simple defun for a region, and I want to apply it even if there's no region – i.e. call it with no selection at all. I thought I could do something like the following:
(defun region-study (strt end)
(interactive "r")
(if (= strt end)
(progn ....) ;; then
(progn ....))) ;; else
But it doesn't work. As it turns out, when you call (interactive "r") with no region it doesn't just set boundaries to be equal. Try this:
(defun region-study (strt end)
(interactive "r")
(message "strt=%d; end=%d" strt end))
So my question is that: "how to write a defun which acts on region, but acts on point if there's no region?"
Edit:
So I wanted to put selection in brackets or just to insert brackets and (backward-char 1). Here's a solution:
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(progn
(setq pP (point))
(setq strt (region-beginning))
(setq end (region-end))
(setq meat (buffer-substring-no-properties strt end))
(setq news (concat lft meat rit))
(delete-region strt end)
(goto-char strt)
(insert news)
(if (= pP strt)
(goto-char strt) ; then
(goto-char (+ end 1)))) ; else
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
(defun bk-put-in-braces ()
(interactive)
(put-in-lft-rit "(" ")"))
(defun bk-put-in-curly-braces ()
(interactive)
(put-in-lft-rit "{" "}"))
(defun bk-put-in-quotes ()
(interactive)
(put-in-lft-rit "'" "'"))
(defun bk-put-in-double-quotes ()
(interactive)
(put-in-lft-rit "\"" "\""))
(defun bk-put-in-square-brackes ()
(interactive)
(put-in-lft-rit "[" "]"))
And then you bind in .emacs:
(global-set-key (kbd "C-<f9>") 'bk-put-in-square-brackes)
(global-set-key (kbd "<f9>") 'bk-put-in-curly-braces)
(global-set-key (kbd "S-<f7>") 'bk-put-in-quotes)
(global-set-key (kbd "S-<f8>") 'bk-put-in-double-quotes)
(global-set-key (kbd "S-<f9>") 'bk-put-in-braces)
That's it! Should be working in all modes.
Edit2:
#phils
Thanks. You are definetely right. One thing though - my code had an additional feature of leaving the point at the beginning or end of the region - depending on where it was in the selection. Here's Your code with this feature added:
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(let ((strt (region-beginning))
(end (region-end))
(pP (point)))
(save-excursion
(goto-char end)
(insert rit)
(goto-char strt)
(insert lft))
(if (= pP strt)
(goto-char strt) ; then
(goto-char (+ end 1)))) ; else
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
A few notes on your solution...
It's good practice to avoid unnecessary global-scope setqs. Use (let) instead to define a temporary scope for your variables.
You are doing a lot more work than required. Instead of copying the region, concatenating that copy and the delimiters into a 'news' variable, deleting the region, and then inserting 'news', all you need to do is insert the delimiter characters at the beginning and end of the region.
(In general, if you try to "think like an editor" when writing elisp, and focus on manipulating buffers rather than variables, you'll generally wind up with more efficient code.)
save-excursion is very useful (along with several other save- and with- forms).
 
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(let ((strt (region-beginning))
(end (region-end)))
(save-excursion
(goto-char end)
(insert rit)
(goto-char strt)
(insert lft)))
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
use-region-p should return t if your function should act on the region instead of at a point.
You may like to use the function region-or-word-at-point defined in thingatpt+.el