0

So i basically want to (as the title suggest) to center a region of text, in the center of the screen. Current example is using part of this site.

From this

To this

And here a small gif video to show how i did it manually (for more detail):

  • Used screenkey to display the key i used. Roughly, i'm just putting a newline characters in front of the first line of the block of text (which is on the same line, in this example) and center it (very roughly) in the center.

  • Then i input space characters in front of each line, until it is formatted into one block of text, in the position i choose above.

This is basically what i want to do (on a region selected text) but in elisp.

Nordine Lotfi
  • 357
  • 2
  • 13
  • So you really want to potentially modify your buffer, by adding empty lines at the beginnig (if necessary) and adding spaces on the left (if necessary) in order to center the block of text? – NickD May 16 '20 at 11:54
  • 1
    Saying buffer but meaning window ? – Muihlinn May 16 '20 at 12:49
  • Yep! @NickD Exactly – Nordine Lotfi May 16 '20 at 19:27
  • @Muihlinn Exactly (though i did correct myself in the post by saying "screen" instead) – Nordine Lotfi May 16 '20 at 19:27
  • What complicates this is that you have a single (long) line of text, but you expect to center it as a block. IOW, you will need to calculate the physical height and width of the block which depends on the frame/window size: if you make it smaller, it'll take fewer physical lines, so it will affect the top-to-bottom centering. Also it's not clear what left-to-right centering means in this case, since the line is longer than the frame/window is wide. Why should there be any space on the left or right? – NickD May 16 '20 at 19:39
  • Why should there be any space on the left or right? mostly for focusing on a text block, in a temp buffer (i didn't plan on doing this on a real file anyway, just temp buffer) @NickD and yes, i already slightly know that to know the center of the screen, i need to calculate the height of the display (1366x768, so the latter) by 2, then need to calculate which width to reformat the text in...(this is where i'm kind of stuck) but at least i know how to do this manually, just need to do it in elisp too :) – Nordine Lotfi May 16 '20 at 19:43
  • What I mean is that your example does not make sense: it shows a single line of text that is wrapped, so it looks like a block, but is a single line of text. In the "after" image, you show it as an indented block but the fringe still shows that the whole thing is a single logical line: IOW, you will have to introduce spaces in the middle of the string - and then if you change window size, you will have to recalculate everything. IMO, you have not specified the problem sufficiently well to even attempt an implementation yet. – NickD May 16 '20 at 19:50
  • Yeah, you're right. I didn't specify anything on the off chance i change windows size, since i didn't really mind if it wrecked the formatting...and I didn't need to introduce space in the middle of the string, just on the side :) (i can update my post and post a gif of me formatting the text manually?) – Nordine Lotfi May 16 '20 at 19:55
  • I think a description of how you go from the initial state to the final state should be enough. But one thing that I would like to see is what happens to your final state if you increase the width of the frame. – NickD May 16 '20 at 20:18
  • gotcha, i'll update the post with those details then! – Nordine Lotfi May 16 '20 at 20:24
  • done updating the post! feel free to tell me if there anything i missed. @NickD – Nordine Lotfi May 16 '20 at 23:54
  • Did you try making the frame bigger (or smaller) as I asked you? What did you observe? – NickD May 17 '20 at 00:35
  • I tried making the frame smaller yes, but i noticed that this wasn't the same thing i wanted (as i showed in the gif and the two pics) since the part that are filled with space on the sides, have a purpose later on (either filled with some markup or something i might come up with on the way)for now i just know that i want it to be have those space as i mentioned :) @NickD (so reducing the frame would prevent this to happen as effectively, and making it bigger isn't really gonna work) – Nordine Lotfi May 17 '20 at 00:46
  • also, if you meant that changing the frame/windows to see what would happen after i made the change i showed, then yes, i did that too :) (it basically wreck the text output afaik) but i don't plan on changing the frame size, and i always use one window only these days, so not a problem. – Nordine Lotfi May 17 '20 at 00:50
  • If you intend just pretty display, see this: https://github.com/rnkn/olivetti, which "Set a desired text body width to automatically resize window margins to keep the text comfortably in the middle of the window." (quoted from link). It works just for pretty display, but not saving. Take into account the example shown in your site link is a .html page, which is a different thing. – Ian May 17 '20 at 11:41

1 Answers1

1

Here's an implementation of exactly what the OP is asking for, although I don't think it is of any use to anybody (except possibly the OP, but even there I have my doubts, as the extended discussion in the comments shows). It assumes that there is one long line starting at the beginning of the buffer and that you want to reformat it as a block of some specified width that is centered in the window of the buffer.

(defun insertN (c count)
   (insert (make-string count c)))

(defun center-block (text-width)
  "Assumption: there is one long line at the beginning of the buffer which this function
           is going to mangle in order to center it in the window.
   Assumption: the given text-width is smaller than the window body width."
  (interactive "NText width: ")

  (let* ((s (buffer-substring-no-properties (point-min) (point-max)))
     (slen (length s))
     (W (window-body-width))
     (H (window-body-height))
     (L text-width)
     (nlines (/ (+ slen L) L))           ; number of physical lines of block
                                         ; when shrunk to the required line length
     (toplines (/ (+ (- H nlines) 2) 2)) ; how many lines to leave at the top
     (lspaces (/ (- W L) 2))             ; how many spaces to insert at the beginning
     (rspaces (- (- W L) lspaces))       ; how many spaces to go to the right end of the window
     (nspaces (+ lspaces rspaces))       ; how many spaces to insert between physical lines
     sub)
    (erase-buffer)
    ;; insert the proper number of newlines
    (insertN ?\n toplines)
    ;; insert the proper number of spaces at the beginning of the string
    (insertN ?\s lspaces)
    ;; break up the string into substrings of length L and insert each
    ;; one, followed by the appropriate number of spaces. The loop inserts
    ;; the *full* logical lines of the block: there might be a tail that is
    ;; left over if the length of the string is not a multiple of L which is
    ;; inserted after the loop is done.
    (while (>= (length s) L)
      (setq sub (substring s 0 L))       ; first L chars
      (setq s (substring s L))           ; rest
      ;; insert the substring
      (insert sub)
      ;; insert nspaces spaces: rspaces to reach the right end of the window
      ;; and lspaces to indent the next physical line.
      (insertN ?\s  nspaces))
    ;; insert what's left over.
    (insert s)))

I have commented it copiously in an attempt to make it understandable to the OP.

Invoke it with M-x center-block RET 60 RET (or whatever width you want to specify instead of 60) while the cursor is in the window of the buffer that you are trying to modify.

NickD
  • 29,717
  • 3
  • 27
  • 44