How to call a function interactively - emacs

When I start up Emacs, I want it to fill the left half of my screen. I accomplish this using
;; set initial window size to the left half of the screen
(defun set-frame-pixel-size (frame width height)
"Sets size of FRAME to WIDTH by HEIGHT, measured in pixels."
(let ((pixels-per-char-width (/ (frame-pixel-width) (frame-width)))
(pixels-per-char-height (/ (frame-pixel-height) (frame-height))))
(set-frame-size frame
(floor (/ width pixels-per-char-width))
(floor (/ height pixels-per-char-height)))))
(defun use-left-half-screen ()
(interactive)
(let* ((excess-width 32)
(excess-height 48)
(half-screen-width (- (/ (x-display-pixel-width) 2) excess-width))
(screen-height (- (x-display-pixel-height) excess-height)))
(set-frame-pixel-size (selected-frame) half-screen-width screen-height)))
(if window-system
(use-left-half-screen))
And it works beautifully. However, I sometimes want to call that same command another time during the day. Hence, I do M-x use-left-half-screen but nothing happens.
That is, unless I run M-: (set-frame-pixel-size (selected-frame) 1024 768) (or something similar) first. If I do that, and I don't change the frame size using my mouse, then use-left-half-screen works. As soon as I change the frame size using the mouse or an OS shortcut, it ceases to work.
Do you have any ideas of how I can make M-x use-left-half-screen work?

Related

Increase/decrease font size in an emacs frame (not just buffer)

Using C-x C-+ and C-x C-- (text-scale-adjust) is very convenient to increase/decrease the font size in one buffer. This is nice to reduce head bumping when a few people work together in front of the same monitor.
Is there a way to increase (and later decrease) the font size in one frame (or all frames simultaneously)? I am wondering if there is a way faster than 1- retyping C-x C-+ in each new buffer, 2- Calling M-x x-select-font and using the mouse to choose, and 3- running elisp code in the scratch buffer.
Update:
If you are interested in satisfying not just 1-3 above but also:
4- Keep the size (and position) of the frame still.
Then look at this question.
See the Emacs Wiki page about frame zooming.
It tells you about several ways to do this, including commands from libraries zoom-frm.el, doremi-frm.el, and frame-cmds.el.
In particular, the single command zoom-in/out lets you zoom either a frame or a buffer in or out. (The former: zooming a frame, is what you requested.)
Based on #Jordon Biondo's answer, this is an alternative solution that solves the collateral effect of changing the frame's size by using set-frame-font with the argument KEEP-SIZE equals to t.
;; Resize the whole frame, and not only a window
;; Adapted from https://stackoverflow.com/a/24714383/5103881
(defun acg/zoom-frame (&optional amt frame)
"Increaze FRAME font size by amount AMT. Defaults to selected
frame if FRAME is nil, and to 1 if AMT is nil."
(interactive "p")
(let* ((frame (or frame (selected-frame)))
(font (face-attribute 'default :font frame))
(size (font-get font :size))
(amt (or amt 1))
(new-size (+ size amt)))
(set-frame-font (font-spec :size new-size) t `(,frame))
(message "Frame's font new size: %d" new-size)))
(defun acg/zoom-frame-out (&optional amt frame)
"Call `acg/zoom-frame' with negative argument."
(interactive "p")
(acg/zoom-frame (- (or amt 1)) frame))
(global-set-key (kbd "C-x C-=") 'acg/zoom-frame)
(global-set-key (kbd "C-x C--") 'acg/zoom-frame-out)
(global-set-key (kbd "<C-down-mouse-4>") 'acg/zoom-frame)
(global-set-key (kbd "<C-down-mouse-5>") 'acg/zoom-frame-out)
This is not the most correct way to do it, I have in the past use these functions to do frame by frame resizing:
In this case it is done by changing the :height attribute of the default face.
(defun zoom-frame (&optional n frame amt)
"Increase the default size of text by AMT inside FRAME N times.
N can be given as a prefix arg.
AMT will default to 10.
FRAME will default the selected frame."
(interactive "p")
(let ((frame (or frame (selected-frame)))
(height (+ (face-attribute 'default :height frame) (* n (or amt 10)))))
(set-face-attribute 'default frame :height height)
(when (called-interactively-p)
(message "Set frame's default text height to %d." height))))
(defun zoom-frame-out (&optional n frame amt)
"Call `zoom-frame' with -N."
(interactive "p")
(zoom-frame (- n) frame amt))
(global-set-key (kbd "C-c z i") 'zoom-frame)
(global-set-key (kbd "C-c z o") 'zoom-frame-out)
This scales the whole frame, not just the text, so it'll shrink or grow on your desktop, possibly growing outside the visibility bounds and requiring a redraw from your OS.
Another possible solution is which I may look into, is setting a frame local variable to a desired height and using a hook that runs each time a buffer is selected to redisplay the text in that buffer to the frame's desired size. This would work decently well unless a buffer was shown on two frames.
You can change font size for all frames using the command line
$ emacsclient -e "(set-face-attribute 'default nil :height 180)"
Change the height value to your needs.
Then bind that command to an alias or a shortcut your window manager provides.
An easy solution
I noticed that although I usually use C-x + to zoom in, I could do the same with C-+. This led me to a nice observation:
I can hold down a button (C) and then press another button repeatedly (+) to zoom.
This means that I can keep the behaviour of C-x + to affect the zoom of only current buffer, while having another key C-+ to affect zoom of the entire frame. This in my opinion is nice behaviour - your requirements may vary. The code is quite simple as well:
(defvar face-attribute-height 125
"Default font face height when Emacs starts.")
(defun face-attribute-height-increase ()
(interactive)
(setq face-attribute-height (+ face-attribute-height 5))
(set-face-attribute 'default nil :height face-attribute-height)
)
(defun face-attribute-height-decrease ()
(interactive)
(setq face-attribute-height (- face-attribute-height 5))
(set-face-attribute 'default nil :height face-attribute-height)
)
(define-key global-map (kbd "C-+") 'face-attribute-height-increase)
(define-key global-map (kbd "C--") 'face-attribute-height-decrease)
I'm not an "expert" elisp-coder, and it can probably be written better. Feedback is welcome!
See http://www.emacswiki.org/emacs/GlobalTextScaleMode, or for a more general explanation:
http://www.emacswiki.org/emacs/SetFonts#toc6

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

Setting Both `fullheight` and `width` in Emacs on OS X

I find the default size of the Emacs frame a little too small. From reading around I know that I can set the height and width quite easily with something like the following:
;;; 140 x 60 window size
(setq default-frame-alist '((width . 140) (height . 60)))
Which works great on my external monitor, however it is a litte too big for the laptop display. I can solve the height problem by changing to the follwing:
;;; automatically set the height
(setq default-frame-alist '((fullscreen . fullheight)))
Which sets the frame to be as tall as possible for the current screen. I can't however set the width of the frame if I use this method. Adding (width . 140) to the above alist sets the width to the right value but also sets the height to the default height again.
When I see the frame appear it sets itself to the full height, and then sets the width to the value I requested, and shrinks in height.
I can overcome this problem with the following code:
;;; Full height for the default window
(setq default-frame-alist
'((fullscreen . fullheight)))
;; Set the width in a hook and have all windows inherit
(setq frame-inherited-parameters
'(width height))
(add-hook 'after-init-hook
(lambda ()
(set-frame-parameter nil 'width 140)))
Which uses a hook to set the width of the first frame to the value I want, and then sets all other windows to inherit this value.
This isn't very elegant however, so the question is "how can I accomplish this in a simpler (or less hackish) way?".
If you want to see my exact init.el script, take a look at this gist
TL;DR
How can I set both the width of a frame, and set the frame to be as tall as possible on the current monitor, on OS X? It seems you can't specify (width . 140) and (fullscreen . fullheight) in the default-frame-alist.
I have come up with a solution to this. I explicitly calculate the height of the window rather than relying on (fullscreen . fullheight) to do it for me.
The updated code to set the values for the height and width is quite simple:
;;; Nice size for the default window
(defun get-default-height ()
(/ (- (display-pixel-height) 120)
(frame-char-height)))
(add-to-list 'default-frame-alist '(width . 140))
(add-to-list 'default-frame-alist (cons 'height (get-default-height)))
In this code the subtraction of 120 from the height of the screen makes sure that the height of the window takes into account the height of the dock and the menubar. For correct results you will have to make sure that this code is executed after you have chosen the font face to use, otherwise the computed height value will not be valid.
Placing the height calculation in its own function should allow special casing certain operating systems and versions. This method also has the added advantage that is faster to open the window as it doesn't "animate" the height to the full height value.
The last paragraph of the help text for display-pixel-height is:
For graphical terminals, note that on "multi-monitor" setups this
refers to the pixel height for all physical monitors associated
with DISPLAY. To get information for each physical monitor, use
‘display-monitor-attributes-list’.
What got me to this page is what looks like a bug in the X11 implementation but I'm not sure yet. In any case, display-pixel-height works only often but not always.
Sample output from display-monitor-attributes-list is:
(
(
(geometry 0 0 1920 1080)
(workarea 0 25 1920 1055)
(mm-size 478 268)
(frames #<frame *scratch* 0x14489a030>)
(source . "NS")
)
(
(geometry 192 1080 1512 982)
(workarea 192 1080 1512 950)
(mm-size 301 195)
(frames)
(source . "NS")
)
)
In my case, I have a laptop (bottom entry) and a monitor connected to it (the top entry).
One possible solution would be to go through the list, find the monitor with the largest height and do the computations based upon that height and then at the end also do something like (set-frame-position nil 192 1080) where the two coordinates come from the top and left coordinates (the first two values of geometry and work area of the monitor that has the greatest height.
It appears that the workarea is the more prudent set of values to use.
And to further make a robust solution, a hook should be added to window-configuration-change-hook so that when a monitor is added or removed, things will get updated.
I am currently asking some questions on the Emacs developers mailing list and working on a solution for myself. I plan to return and update this entry when I have a solution that I'm happy with but thought this information may be of use to others as is.
Update:
There is no bug. x-display-pixel-height has various X11 rude facts of life. For more details, see this reply.
The "Frame Layout" node in the info documentation for ELisp as a description of the Inner and Outer Frame along with many other concepts that are pertinent to this question.
Here is my current solution. I have not done the hook yet. I don't claim to know how to program in lisp but this code is working for me.
(defun workarea-height ( monitor )
"MONITOR is an entry from `display-monitor-attributes-list' The
height entry (4th value) of the 'workarea' is returned"
(nth 4 (assoc 'workarea monitor)))
(defun monitor-with-largest-height-helper ( a b )
"Compares the height of the workarea of two monitor entries such as
those contained in the output of `display-monitor-attributes-list'"
(let* ((a-height (workarea-height a))
(b-height (workarea-height b)))
(if (> a-height b-height)
a
b)))
(defun monitor-with-largest-height ()
"Returns the monitor entry from `display-monitor-attributes-list'
with the largest 'workarea' height"
(cl-reduce #'monitor-with-largest-height-helper
(display-monitor-attributes-list)))
(defun largest-monitor-height ()
"Returns the usable height in lines of the largest monitor currently
attached"
(let* ((largest-monitor (monitor-with-largest-height)))
(/ (- (workarea-height largest-monitor)
(- (frame-outer-height)
(frame-inner-height)))
(frame-char-height))))
(defun my-resize-frame-height ()
"Resizes the current frame to the full height of the largest monitor
currently attached."
(interactive)
(set-frame-height nil (largest-monitor-height)))
The other work left to do is to make sure the left and top of the frame are within the area of the largest monitor to the frame will be displayed on that monitor.

How to resize a buffer so it only takes a small part of the screen?

In Emacs how can I resize a buffer so it only takes a small part of the screen ?
Is there any way ?
I would like to have the src taking 70% of the screen and a file manager in the other 30%
Set width of current window on current frame to ~ 70%:
(window-resize nil (- (truncate (* 0.7 (frame-width))) (window-width)) t)
The other windows are shrunk automatically. If you want to adjust more than one it gets more difficult.
As command:
(defun window-resize-to-70-percent ()
(interactive)
(window-resize nil (- (truncate (* 0.7 (frame-width))) (window-width)) t))
Use separate window-manager frames for individual buffers (by default). Automatically shrink-fit the frames to fit the buffer content.
See One-On-One Emacs, in particular, libraries fit-frame.el and autofit-frame.el.

How do I set the size of Emacs' window?

I'm trying to detect the size of the screen I'm starting emacs on, and adjust the size and position the window it is starting in (I guess that's the frame in emacs-speak) accordingly. I'm trying to set up my .emacs so that I always get a "reasonably-big" window with it's top-left corner near the top-left of my screen.
I guess this is a big ask for the general case, so to narrow things down a bit I'm most interested in GNU Emacs 22 on Windows and (Debian) Linux.
If you want to change the size according to resolution you can do something like this (adjusting the preferred width and resolutions according to your specific needs):
(defun set-frame-size-according-to-resolution ()
(interactive)
(if window-system
(progn
;; use 120 char wide window for largeish displays
;; and smaller 80 column windows for smaller displays
;; pick whatever numbers make sense for you
(if (> (x-display-pixel-width) 1280)
(add-to-list 'default-frame-alist (cons 'width 120))
(add-to-list 'default-frame-alist (cons 'width 80)))
;; for the height, subtract a couple hundred pixels
;; from the screen height (for panels, menubars and
;; whatnot), then divide by the height of a char to
;; get the height we want
(add-to-list 'default-frame-alist
(cons 'height (/ (- (x-display-pixel-height) 200)
(frame-char-height)))))))
(set-frame-size-according-to-resolution)
Note that window-system is deprecated in newer versions of emacs. A suitable replacement is (display-graphic-p). See this answer to the question How to detect that emacs is in terminal-mode? for a little more background.
I've got the following in my .emacs:
(if (window-system)
(set-frame-height (selected-frame) 60))
You might also look at the functions set-frame-size, set-frame-position, and set-frame-width. Use C-h f (aka M-x describe-function) to bring up detailed documentation.
I'm not sure if there's a way to compute the max height/width of a frame in the current windowing environment.
Taken from: http://www.gnu.org/software/emacs/windows/old/faq4.html
(setq default-frame-alist
'((top . 200) (left . 400)
(width . 80) (height . 40)
(cursor-color . "white")
(cursor-type . box)
(foreground-color . "yellow")
(background-color . "black")
(font . "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1")))
(setq initial-frame-alist '((top . 10) (left . 30)))
The first setting applies to all emacs frames including the first one that pops up when you start. The second setting adds additional attributes to the first frame. This is because it is sometimes nice to know the original frame that you start emacs in.
Try adding the following code to .emacs
(add-to-list 'default-frame-alist '(height . 24))
(add-to-list 'default-frame-alist '(width . 80))
The easiest way I've found to do that in an X-Window environment is through X resources. The relevant part of my .Xdefaults looks like this:
Emacs.geometry: 80x70
You should be able to suffix it with +0+0 location coordinates to force it to the upper-left corner of your display. (the reason I don't do it is that I occasionnally spawn new frames, and it makes things confusing if they appear in the exact same location as the previous one)
According to the manual, this technique works on MS Windows too, storing the resources as key/value pairs in the registry. I never tested that. It might be great, it might be much more of an inconvenience compared to simply editing a file.
You can also the -geometry parameter when firing up emacs: emacs -geometry 80x60+20+30 will give you a window 80 characters wide, 60 rows high, with the top left corner 20 pixels to the right and 30 pixels down from the top left corner of the background.
On ubuntu do:
(defun toggle-fullscreen ()
(interactive)
(x-send-client-message nil 0 nil "_NET_WM_STATE" 32
'(2 "_NET_WM_STATE_MAXIMIZED_VERT" 0))
(x-send-client-message nil 0 nil "_NET_WM_STATE" 32
'(2 "_NET_WM_STATE_MAXIMIZED_HORZ" 0))
)
(toggle-fullscreen)
On windows, you could make emacs frame maximized using this function :
(defun w32-maximize-frame ()
"Maximize the current frame"
(interactive)
(w32-send-sys-command 61488))
(setq initial-frame-alist
(append '((width . 263) (height . 112) (top . -5) (left . 5) (font . "4.System VIO"))
initial-frame-alist))
(setq default-frame-alist
(append '((width . 263) (height . 112) (top . -5) (left . 5) (font . "4.System VIO"))
default-frame-alist))
(defun set-frame-size-according-to-resolution ()
(interactive)
(if window-system
(progn
;; use 120 char wide window for largeish displays
;; and smaller 80 column windows for smaller displays
;; pick whatever numbers make sense for you
(if (> (x-display-pixel-width) 1280)
(add-to-list 'default-frame-alist (cons 'width 120))
(add-to-list 'default-frame-alist (cons 'width 80)))
;; for the height, subtract a couple hundred pixels
;; from the screen height (for panels, menubars and
;; whatnot), then divide by the height of a char to
;; get the height we want
(add-to-list 'default-frame-alist
(cons 'height (/ (- (x-display-pixel-height) 200)
(frame-char-height)))))))
(set-frame-size-according-to-resolution)
I prefer Bryan Oakley's settings. However the 'height not work properly in my GNU Emacs 24.1.1.