How to interactively read in two inputs and use them in a function call - emacs

I am currently taking a class to learn elisp so I have no experience with this language. I am trying to interactively read in two inputs (the width and length of a rectangle) and then use them to call a function to compute the area of the rectangle. The code I have is as follows:
(defun rectangle_Area(w l)
"Compute the area of a rectangle, given its width and length interactively."
(interactive "nWidth: ")
(interactive "nLength: ")
(setq area (rectangleArea w l))
(message "The rectangle's area is %f." area))
Currently I get a wrong number of arguments error.
Like I said, I have no previous experience... all I really need to know is how to store/read in two separate values using interactive.
Thank you for any help

C-hf interactive RET:
To get several arguments, concatenate the individual strings,
separating them by newline characters.
So we have:
(defun rectangle_Area(w l)
"Compute the area of a rectangle, given its width and length interactively."
(interactive "nWidth: \nnLength: ")
(setq area (rectangleArea w l))
(message "The rectangle's area is %f." area))

Related

AutoCAD (also LT) combox control in plot window, ChooseString not finding printer

I made an AutoHotkey script to print drawings to PDF; however, I am having issues with a particular combobox in AutoCAD's plot dialog box. This combobox allows you to select one of your installed printers or printer configuration files. The printer I want to choose is one of the built-in ones, called "DWG To PDF.pc3". Here is my code snippet that DOESN'T work (it appears to do nothing):
Control , ChooseString , DWG , ComboBox1 , Plot - Model
Additionally, I've tried with and without quotes (it's always hard for me to tell when I need to quote literal text) and the full name -- nothing works. My workaround (temporarily, I hope) is to use Control , Choose , N. This is undesirable as different users may have more or fewer printers installed and this will affect where the desired printer is placed in the list. Here is a snippet of that code:
Control , Choose , 20 , ComboBox1 , Plot - Model
For reference, I have installed AutoHotkey version 1.1.30.01 - November 11, 2018.
What am I missing? Or any suggestions or creative solutions (even from other programming languages)? Thank you!
EDIT:
TL;DR - This is mainly geared for LT.
Full Context - I have full AutoCAD (Mechanical) and use LISP for many tasks. In fact, I've used your (Lee Mac's) tutorials and helpful posts across many forums to get started with it years ago. At my company, we have 27 seats of LT (11 full) where I've set up a company ribbon with SCR files for a few things, including printing. This case is a little different because some of the users need to be able to select a few different pre-configured print options.
Of course, I could make more SCR files for this purpose, but they lack user-error-prevention that AHK can provide. Really, I have a working program with AHK, but it's just short of meeting my standard since there seems to be something goofy going on with just that one particular combobox. So, if someone could steer me towards figuring that out, I would greatly appreciate it.
Firstly, it would be helpful if you could clarify whether the host application is the full version of AutoCAD or the lite version AutoCAD LT, since the former supports full customisation using the AutoLISP, .NET, or ObjectARX APIs (and hence this task is straightforward) whereas the latter does not support customisation, meaning third-party tools (such as AutoHotKey) must be used.
If you have access to the full version of AutoCAD, then the task of plotting to a PDF can be accomplished with an AutoLISP program such as the following:
(defun c:pdfall ( / *error* cmd ctb )
(defun *error* ( msg )
(if ctb (setvar 'ctab ctb))
(if cmd (setvar 'cmdecho cmd))
(if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
(princ (strcat "\nError: " msg))
)
(princ)
)
(setq ctb (getvar 'ctab)
cmd (getvar 'cmdecho)
)
(setvar 'cmdecho 0)
(foreach lay (layoutlist)
(setvar 'ctab lay)
(command
"_.-plot"
"_Y" ;; Detailed plot configuration? [Yes/No]:
"" ;; Enter a layout name <Current-Layout>:
"DWG To PDF.pc3" ;; Enter an output device name:
"ISO full bleed A4 (297.00 x 210.00 MM)" ;; Enter paper size:
"_M" ;; Enter paper units [Inches/Millimeters]:
"_L" ;; Enter drawing orientation [Portrait/Landscape]:
"_N" ;; Plot upside down? [Yes/No]:
"_E" ;; Enter plot area [Display/Extents/Limits/View/Window]:
"_F" ;; Enter plot scale (Plotted Inches=Drawing Units) or [Fit] <1=1>:
"_C" ;; Enter plot offset (x,y) or [Center]:
"_Y" ;; Plot with plot styles? [Yes/No]:
"monochrome.ctb" ;; Enter plot style table name (enter . for none):
"_Y" ;; Plot with lineweights? [Yes/No]:
"_N" ;; Scale lineweights with plot scale? [Yes/No]:
"_N" ;; Plot paper space first? [Yes/No]:
"_N" ;; Hide paperspace objects? [Yes/No]:
(LM:uniquefilename (strcat (getvar 'dwgprefix) lay ".pdf"))
"_N" ;; Save changes to page setup [Yes/No]:
"_Y" ;; Proceed with plot [Yes/No]:
)
)
(setvar 'ctab ctb)
(setvar 'cmdecho cmd)
(princ)
)
;; Unique Filename - Lee Mac
;; Returns a filename suffixed with the smallest integer required for uniqueness
(defun LM:uniquefilename ( fnm )
(if (findfile fnm)
(apply
'(lambda ( pth bse ext / tmp )
(setq tmp 1)
(while (findfile (setq fnm (strcat pth bse "(" (itoa (setq tmp (1+ tmp))) ")" ext))))
)
(fnsplitl fnm)
)
)
fnm
)
(princ)
However, assuming you only have access to the basic AutoCAD LT platform, I would suggest using the command-line version of the PLOT command: -PLOT, so that you only need to supply keyboard input to a predictable sequence of prompts, rather than interacting with a dialog interface which differs depending on the last used settings.
When using the -PLOT command, the sequence of prompts for a Paperspace Layout will be as shown in the AutoLISP program posted above, i.e.:
"_.-plot"
"_Y" ;; Detailed plot configuration? [Yes/No]:
"" ;; Enter a layout name <Current-Layout>:
"DWG To PDF.pc3" ;; Enter an output device name:
"ISO full bleed A4 (297.00 x 210.00 MM)" ;; Enter paper size:
"_M" ;; Enter paper units [Inches/Millimeters]:
"_L" ;; Enter drawing orientation [Portrait/Landscape]:
"_N" ;; Plot upside down? [Yes/No]:
"_E" ;; Enter plot area [Display/Extents/Limits/View/Window]:
"_F" ;; Enter plot scale (Plotted Inches=Drawing Units) or [Fit] <1=1>:
"_C" ;; Enter plot offset (x,y) or [Center]:
"_Y" ;; Plot with plot styles? [Yes/No]:
"monochrome.ctb" ;; Enter plot style table name (enter . for none):
"_Y" ;; Plot with lineweights? [Yes/No]:
"_N" ;; Scale lineweights with plot scale? [Yes/No]:
"_N" ;; Plot paper space first? [Yes/No]:
"_N" ;; Hide paperspace objects? [Yes/No]:
<Your PDF Filename Here>
"_N" ;; Save changes to page setup [Yes/No]:
"_Y" ;; Proceed with plot [Yes/No]:

Moving point to the end of the last line without reorienting the buffer

Is it possible to move point to the end of a buffer without reorienting the text around that line? This seems to be the default behaviour of goto-char. My goal is to correct a minor annoyance which places the cursor at the second last line when I press "L". I wrote a custom function to do this properly but now when I move the point to the last line the screen scrolls down half a page and it becomes the center of the buffer.
(defun cf-last-line (count) (interactive "p")
(let ((max (truncate (window-screen-lines))))
(move-to-window-line max)
(line-move (* -1 (1- count)) t t)
(beginning-of-line)))
Edit: It turns out my problem is related to the fact that the GUI shows partial lines (which may appear to be fully exposed but upon closer inspection lie just below the status bus). I suppose my question then becomes whether or not it is possible to have the point lie on such a partial line (though I suspect this is unlikely) without moving it to the center and if not whether it is possible to instead prevent the X11 frame from showing partial lines at the bottom of the window.
Solution as described by lawlist:
(setq scroll-conservatively 101)
(setq make-cursor-line-fully-visible nil)

Centre Emacs buffer within window

I wrap all my code at 80 columns, and there are times where the Emacs window is wider than 80 columns and there is a lot of unused whitespace on the right side.
I would like to position the Emacs buffer, so all the text is displayed in the middle of the window.
This is different to centre aligning text (more akin to the whitespace on either side of the text when viewing pdfs).
I think this can be achieved by dynamically adjusting the fringe mode widths, depending on the current window size, but I'm not sure where to start. Any ideas?
As demonstrated here this is indeed possible:
(set-fringe-mode
(/ (- (frame-pixel-width)
(* 80 (frame-char-width)))
2))
However, as I am testing this I seem to have more luck with using margins, at least when also resizing my frame:
(defun my-resize-margins ()
(let ((margin-size (/ (- (frame-width) 80) 2)))
(set-window-margins nil margin-size margin-size)))
(add-hook 'window-configuration-change-hook #'my-resize-margins)
(my-resize-margins)
Here is a function which should do what you want, using margins instead of fringes (since I tend to display buffer boundaries in the fringe and I find it becomes ugly if the fringe is too large).
(defun my/center (width)
(interactive "nBuffer width: ")
(let* ((adj (- (window-text-width)
width))
(total-margin (+ adj
left-margin-width
right-margin-width)))
(setq left-margin-width (/ total-margin 2))
(setq right-margin-width (- total-margin left-margin-width)))
(set-window-buffer (selected-window) (current-buffer)))
You ask to display the buffer in the center of the window, which just moves some of the extra whitespace to the left of the buffer, from the right.
How about a solution that eliminates that extra whitespace instead? If that is acceptable, here are two approaches.
If the buffer is alone in its frame, then you can fit the frame to the buffer, using library fit-frame.el. I bind command fit-frame to C-x C-_. This saves space not only within Emacs but for your desktop. (Library zoom-frm.el lets you also shrink/enlarge a frame incrementally, so you can save space by shrinking a frame when you don't need to see its content in detail.)
If not (so the buffer is shown in a frame where there are multiple windows), and if the buffer's window has another window to the left or right of it, then you can do one of the following:
2a. If the buffer's window has another window to the left or right of it, then you can use command fit-window-to-buffer. But you will also need to set option fit-window-to-buffer-horizontally to non-nil.
2b. Use C-{ (shrink-window-horizontally), followed by C-x z z z..., to incrementally shrink the window width (removing the extra whitespace).
2c. Load library face-remap+.el. Whenever you use text-scaling (e.g. C-x C- or C-x =), the window size grows or shrinks along with the text size, so you don't get extra whitespace added at the right when you shrink the text. This is controlled by user option text-scale-resize-window.
Center window mode
https://github.com/anler/centered-window-mode
Global minor mode that centers the text of the window.
If another window is visible the text goes back to normal if its width is less than "cwm-centered-window-width."
Modern answer is https://github.com/rnkn/olivetti or https://github.com/joostkremers/writeroom-mode, both worked immediately for me where other things did not

Is It Possible To Replace Fringe Bitmaps With Text in Emacs?

I'd love to replace the ugly pixel arrows indicating truncated or wrapped lines with simple, tasteful text (maybe even a nice unicode character, like a \u2026 ellipsis). Is this possible?
No, it is not. Fringe “bitmaps” are really bitmaps, that is vectors of 0/1 bits, overlayed over the fringe. There is no way to directly render arbitrary unicode characters onto the fringe.
What you can do, is to render a unicode character into a 0/1 bitmap yourself. Any decent image editor (e.g. Gimp, Photoshop, Pixelmator, Paint.net, etc.) can do this. Then convert this bitmap into an fringe bitmap vector. The format of fringe bitmaps is described in Customizing Fringe Bitmaps.
Eventually you can use these bitmap vectors to replace the left-arrow, right-arrow (for truncated lines), left-curly-arrow, and right-curly-arrow (for continued lines) bitmaps, using the function define-fringe-bitmap.
However, I'd say that this is more hassle than it is worth. The fringe is 8 pixels wide, so you'd have to squeeze your beautiful unicode character into an 8x8 bitmap. This means no subpixel rendering, no aliasing, no bytecode rendering, nothing of what makes characters on the screen nice and fancy. It'd be just as ugly as the arrows you have replaced.
The answer by lunaryorn is correct, but it is perhaps beyond the reach of novice Emacs users -- e.g., programmer hobbyists such as myself.
The function fringe-helper-convert written by Nikolaj Schumacher in his library Fringe Helper -- https://github.com/nschum/fringe-helper.el -- makes it easy for Emacs hobbyists like myself to create a vector that is used by the the function define-fringe-bitmap (which is defined in the C-source code of Emacs). I chose a pilcrow, but the user is free to create any image that will fit -- e.g., using the capital letter X and the period ., the user could create the shape of a letter.
;; AUTHOR: Nikolaj Schumacher -- https://github.com/nschum/fringe-helper.el
(defun fringe-helper-convert (&rest strings)
"Convert STRINGS into a vector usable for `define-fringe-bitmap'.
Each string in STRINGS represents a line of the fringe bitmap.
Periods (.) are background-colored pixel; Xs are foreground-colored. The
fringe bitmap always is aligned to the right. If the fringe has half
width, only the left 4 pixels of an 8 pixel bitmap will be shown.
For example, the following code defines a diagonal line.
\(fringe-helper-convert
\"XX......\"
\"..XX....\"
\"....XX..\"
\"......XX\"\)"
(unless (cdr strings)
;; only one string, probably with newlines
(setq strings (split-string (car strings) "\n")))
(apply 'vector
(mapcar
(lambda (str)
(let ((num 0))
(dolist (c (string-to-list str))
(setq num (+ (* num 2) (if (eq c ?.) 0 1))))
num))
strings)))
The following example assumes a frame-char-height of 20 pixels -- so that the bitmap image is the same height as the text in the buffer. The let-bound snippet creates a pilcrow shape in the right fringe at the end of the line (wherever point is when the snippet is evaluated). The example assumes the right fringe is at least a width of eleven -- e.g., (add-to-list 'default-frame-alist '(right-fringe . 11)) The unicode symbol converted to string -- (char-to-string ?\uE000) could probably be substituted with " ".
(define-fringe-bitmap 'pilcrow (fringe-helper-convert
"......."
"......."
"......."
"......."
"......."
".XXXXXX"
"XXXX.X."
"XXXX.X."
"XXXX.X."
".XXX.X."
"...X.X."
"...X.X."
"...X.X."
"...X.X."
"...X.X."
"...X.X."
"......."
"......."
"......."
"......."))
(let ((peol (point-at-eol)))
(overlay-put (make-overlay peol peol) 'after-string
(propertize (char-to-string ?\uE000) 'display
'(right-fringe pilcrow font-lock-keyword-face))))

Emacs / Slime / Hard Code Vertical Split Ratio

I'm currently in mode: C-x 2
Normally, I don't care much about vertical splitting. However, I'm coding on a 13" display, which makes vertical space rather precious.
I would like some setup where when I do C-x 2, my window is not split 50/50, but rather 70/30 [this way I can send the repl to the bottom portion of the screen, and stll see quite a bit of code.]
C-h a vertical split
brings up:
split-window-vertically, table-split-call-vertically
However, I suspect there is some parameter that changes / controls the split ratio.
What emacs option tells my computer to split 70/30 rather than 50/50?
Thanks!
You can use a prefix argument to tell Emacs how many lines to give each of the two windows.
See: C-hk C-x2
or C-hf split-window-below RET
If optional argument SIZE is omitted or nil, both windows get the
same height, or close to it. If SIZE is positive, the upper
(selected) window gets SIZE lines. If SIZE is negative, the
lower (new) window gets -SIZE lines.
So you could give the upper window 20 lines and the lower window the remainder with: C-u 20 C-x2
(or M-2M-0C-x2, etc...)
And you could give the lower window 10 lines and the upper window the remainder with: C-u -10 C-x2
(or M--M-1M-0C-x2, etc...)
See How to change size of split screen emacs windows? for lots of ways to modify the size of windows after splitting.
Edit:
You can use the following function to do what you want:
(defun my-split-window-below (&optional arg)
"Split the current window 70/30 rather than 50/50.
A single-digit prefix argument gives the top window arg*10%."
(interactive "P")
(let ((proportion (* (or arg 7) 0.1)))
(split-window-below (round (* proportion (window-height))))))
(global-set-key (kbd "C-c x 2") 'my-split-window-below)
The default ratio is 70/30, but you can supply a single-digit prefix argument to specify the size of the top window in 10% increments.
If you bound this command to C-x2 then C-9C-x2 would give the top window 90% and the bottom 10%.
Edit 2: I ended up using a variation of that as my own C-x2 binding. This version defaults to a normal 50/50 split, but provides the same prefix arg functionality of the other function in case I want something different.
(defun my-split-window-below (&optional arg)
"Split the current window 50/50 by default.
A single-digit prefix argument gives the top window ARG * 10%
of the available lines."
(interactive "P")
(let* ((proportion (and arg (* arg 0.1)))
(size (and proportion (round (* proportion (window-height))))))
(split-window-below size)))